@helioslx/core 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +44 -0
- package/CONTRIBUTING.md +83 -0
- package/LICENSE +256 -0
- package/README.md +159 -0
- package/SECURITY.md +67 -0
- package/dist/contracts-C4kpAdZq.d.ts +265 -0
- package/dist/contracts-C4kpAdZq.d.ts.map +1 -0
- package/dist/http.d.ts +643 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +670 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +270 -0
- package/dist/index.js.map +1 -0
- package/dist/node.d.ts +114 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/node.js +334 -0
- package/dist/node.js.map +1 -0
- package/dist/redis.d.ts +46 -0
- package/dist/redis.d.ts.map +1 -0
- package/dist/redis.js +174 -0
- package/dist/redis.js.map +1 -0
- package/dist/source-DB1oq2GT.js +884 -0
- package/dist/source-DB1oq2GT.js.map +1 -0
- package/dist/source-D_XNWXS9.d.ts +76 -0
- package/dist/source-D_XNWXS9.d.ts.map +1 -0
- package/dist/testing.d.ts +38 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +98 -0
- package/dist/testing.js.map +1 -0
- package/dist/validation-BdsVeyAE.js +151 -0
- package/dist/validation-BdsVeyAE.js.map +1 -0
- package/examples/embedded-elysia-http.ts +30 -0
- package/examples/full-frame-fade.ts +25 -0
- package/examples/graceful-shutdown.ts +19 -0
- package/examples/quickstart.ts +30 -0
- package/examples/redis.ts +30 -0
- package/examples/sparse-channels.ts +23 -0
- package/examples/viewer-subscription.ts +38 -0
- package/examples/viewer-tui.ts +201 -0
- package/package.json +108 -0
- package/src/contracts.ts +302 -0
- package/src/http.ts +1101 -0
- package/src/index.ts +61 -0
- package/src/memory-store.ts +45 -0
- package/src/node.ts +578 -0
- package/src/output-engine.ts +778 -0
- package/src/redis.ts +258 -0
- package/src/source.ts +502 -0
- package/src/testing.ts +139 -0
- package/src/validation.ts +328 -0
- package/src/viewer.ts +368 -0
package/dist/http.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","names":[],"sources":["../src/http.ts"],"sourcesContent":["import { Elysia, t } from \"elysia\";\nimport { openapi } from \"@elysiajs/openapi\";\nimport { node } from \"@elysiajs/node\";\nimport {\n SLOT_COUNT,\n type ChannelValues,\n type ChannelWrite,\n type SacnSourceContract,\n type TransitionWrite,\n type UniverseContract,\n type ViewerPacket,\n type ViewerServiceContract,\n} from \"./contracts.js\";\nimport {\n DependencyUnavailableError,\n PersistenceError,\n SacnLifecycleError,\n SacnValidationError,\n TransportError,\n} from \"./validation.js\";\n\nexport interface HttpAuthContext {\n readonly request: Request;\n}\n\nexport type HttpAuthHook = (\n context: HttpAuthContext,\n) => boolean | Response | void | Promise<boolean | Response | void>;\n\nexport interface SacnHttpAdapterOptions {\n readonly source: SacnSourceContract;\n readonly viewer?: ViewerServiceContract;\n /** Defaults to `/sacn`. */\n readonly prefix?: string;\n /** Authentication hook; returning false produces 401, and Response is forwarded. */\n readonly auth?: HttpAuthHook;\n /** Called for every normalized viewer packet; useful for WebSocket/SSE bridges. */\n readonly onViewerPacket?: (packet: ViewerPacket) => void;\n /** Value used by deprecated compatibility routes. */\n readonly sunset?: string;\n /** OpenAPI document path. Defaults to `/openapi`. */\n readonly openapiPath?: string;\n /** Maximum concurrent viewer WebSocket clients. Defaults to 64. */\n readonly maxWebSocketClients?: number;\n /** Coalesced packet queue per WebSocket client. Defaults to 32 universes. */\n readonly webSocketQueueCapacity?: number;\n}\n\ninterface RouteSet {\n headers: Record<string, string | number>;\n status?: number | string;\n}\n\ninterface OutputParams {\n universe: string;\n priority: string;\n}\n\nconst outputParamsSchema = t.Object({\n universe: t.String({ pattern: \"^-?\\\\d+$\" }),\n priority: t.String({ pattern: \"^-?\\\\d+$\" }),\n});\nconst frameValuesSchema = t.Array(t.Integer({ minimum: 0, maximum: 255 }), {\n minItems: SLOT_COUNT,\n maxItems: SLOT_COUNT,\n});\nconst outputOptionsSchema = {\n cid: t.Optional(t.String()),\n idleFps: t.Optional(t.Number({ exclusiveMinimum: 0, maximum: 1000 })),\n sourceName: t.Optional(t.String({ minLength: 1, maxLength: 64 })),\n};\nconst frameBodySchema = t.Object({\n values: frameValuesSchema,\n durationMs: t.Optional(t.Number({ minimum: 0 })),\n ...outputOptionsSchema,\n});\nconst upsertBodySchema = t.Object({\n initialValues: t.Optional(frameValuesSchema),\n values: t.Optional(frameValuesSchema),\n durationMs: t.Optional(t.Number({ minimum: 0 })),\n ...outputOptionsSchema,\n});\nconst channelWritesSchema = t.Array(\n t.Object({\n channel: t.Integer({ minimum: 1, maximum: SLOT_COUNT }),\n value: t.Integer({ minimum: 0, maximum: 255 }),\n durationMs: t.Optional(t.Number({ minimum: 0 })),\n }),\n { minItems: 1 },\n);\nconst channelsBodySchema = t.Union([\n t.Object({\n channels: t.Union([\n channelWritesSchema,\n t.Record(t.String(), t.Integer({ minimum: 0, maximum: 255 })),\n ]),\n durationMs: t.Optional(t.Number({ minimum: 0 })),\n ...outputOptionsSchema,\n }),\n t.Object({\n changes: channelWritesSchema,\n durationMs: t.Optional(t.Number({ minimum: 0 })),\n ...outputOptionsSchema,\n }),\n]);\nconst outputSnapshotSchema = t.Object({\n activeTransitions: t.Integer({ minimum: 0 }),\n cid: t.String(),\n current: frameValuesSchema,\n dirty: t.Boolean(),\n frameMode: t.Union([t.Literal(\"active\"), t.Literal(\"idle\")]),\n idleFps: t.Number(),\n lastError: t.Union([t.String(), t.Null()]),\n lastSent: frameValuesSchema,\n lastSentAt: t.Union([t.Number(), t.Null()]),\n nextDueAt: t.Number(),\n priority: t.Integer(),\n sequence: t.Integer(),\n sourceName: t.Union([t.String(), t.Null()]),\n target: frameValuesSchema,\n universe: t.Integer(),\n updatedAt: t.Number(),\n});\nconst errorSchema = t.Object({ error: t.String() });\nconst viewerStateSchema = t.Object({\n universes: t.Array(t.Integer({ minimum: 1, maximum: 63_999 })),\n});\nconst engineTelemetrySchema = t.Object({\n closed: t.Boolean(),\n running: t.Boolean(),\n outputCount: t.Integer({ minimum: 0 }),\n outputs: t.Array(outputSnapshotSchema),\n loopIterations: t.Integer({ minimum: 0 }),\n lastLoopStartedAt: t.Union([t.Number(), t.Null()]),\n lastLoopCompletedAt: t.Union([t.Number(), t.Null()]),\n lastLoopDurationMs: t.Union([t.Number(), t.Null()]),\n transport: t.Object({\n sendAttempts: t.Integer({ minimum: 0 }),\n sendFailures: t.Integer({ minimum: 0 }),\n sendRetries: t.Integer({ minimum: 0 }),\n sendSuccesses: t.Integer({ minimum: 0 }),\n sendTimeouts: t.Integer({ minimum: 0 }),\n }),\n});\nconst viewerTelemetrySchema = t.Object({\n droppedUpdates: t.Integer({ minimum: 0 }),\n packetsReceived: t.Integer({ minimum: 0 }),\n selectedUniverses: t.Array(t.Integer()),\n streamCount: t.Integer({ minimum: 0 }),\n});\nconst viewerUniverseParamsSchema = t.Object({\n universe: t.String({ pattern: \"^-?\\\\d+$\" }),\n});\nconst errorResponseDocument = (description: string) => ({\n description,\n content: {\n \"application/json\": {\n schema: { $ref: \"#/components/schemas/Error\" },\n },\n },\n});\nconst outputResponseDocument = {\n 200: {\n description: \"Output snapshot\",\n content: {\n \"application/json\": {\n schema: { $ref: \"#/components/schemas/OutputSnapshot\" },\n },\n },\n },\n 400: errorResponseDocument(\"Invalid request\"),\n 409: errorResponseDocument(\"Lifecycle conflict\"),\n 503: errorResponseDocument(\"Transport or persistence unavailable\"),\n};\nconst outputLookupResponseDocument = {\n ...outputResponseDocument,\n 404: errorResponseDocument(\"Output not found\"),\n};\nconst clearResponseDocument = {\n 200: {\n description: \"Output cleared\",\n content: {\n \"application/json\": {\n schema: {\n type: \"object\",\n required: [\"ok\"],\n properties: { ok: { type: \"boolean\", const: true } },\n },\n },\n },\n },\n 400: errorResponseDocument(\"Invalid request\"),\n 404: errorResponseDocument(\"Output not found\"),\n 409: errorResponseDocument(\"Lifecycle conflict\"),\n 503: errorResponseDocument(\"Transport or persistence unavailable\"),\n};\nconst componentResponse = (schema: string, description: string) => ({\n 200: {\n description,\n content: {\n \"application/json\": {\n schema: { $ref: `#/components/schemas/${schema}` },\n },\n },\n },\n 400: errorResponseDocument(\"Invalid request\"),\n 409: errorResponseDocument(\"Lifecycle conflict\"),\n 503: errorResponseDocument(\"Dependency unavailable\"),\n});\n\nconst integerParam = (value: string, label: string): number => {\n if (!/^-?\\d+$/.test(value)) {\n throw new SacnValidationError(\n `${label} must be an integer.`,\n label === \"Universe\" ? \"INVALID_UNIVERSE\" : \"INVALID_PRIORITY\",\n );\n }\n return Number(value);\n};\n\nconst addressOf = (params: OutputParams) => ({\n universe: integerParam(params.universe, \"Universe\"),\n priority: integerParam(params.priority, \"Priority\"),\n});\n\nconst bodyObject = (body: unknown): Record<string, unknown> => {\n if (!body || typeof body !== \"object\" || Array.isArray(body)) {\n throw new SacnValidationError(\n \"Request body must be an object.\",\n \"INVALID_FRAME\",\n );\n }\n return body as Record<string, unknown>;\n};\n\nconst messageOf = (error: unknown): string =>\n error instanceof Error ? error.message : \"Internal server error.\";\n\nconst statusOf = (error: unknown): number => {\n if (error instanceof SacnValidationError) return 400;\n if (error instanceof SacnLifecycleError) return 409;\n if (\n error instanceof DependencyUnavailableError ||\n error instanceof PersistenceError ||\n error instanceof TransportError\n ) {\n return 503;\n }\n return 500;\n};\n\nconst fail = (set: RouteSet, error: unknown): { error: string } => {\n set.status = statusOf(error);\n return { error: messageOf(error) };\n};\n\nconst deprecated = (\n set: RouteSet,\n successor: string,\n sunset: string,\n): void => {\n set.headers.deprecation = \"true\";\n set.headers.link = `<${successor}>; rel=\"successor-version\"`;\n set.headers.sunset = sunset;\n};\n\nconst channelsFrom = (\n body: unknown,\n): {\n mode: \"set\" | \"fade\" | \"transition\";\n values?: ChannelValues;\n writes?: readonly TransitionWrite[];\n durationMs?: number;\n idleFps?: number;\n sourceName?: string;\n cid?: string;\n} => {\n const record = bodyObject(body);\n const sharedDuration =\n typeof record.durationMs === \"number\" ? record.durationMs : undefined;\n const value = record.channels ?? record.changes;\n const options = {\n ...(sharedDuration === undefined ? {} : { durationMs: sharedDuration }),\n ...(record.idleFps === undefined\n ? {}\n : { idleFps: record.idleFps as number }),\n ...(record.sourceName === undefined\n ? {}\n : { sourceName: record.sourceName as string }),\n ...(record.cid === undefined ? {} : { cid: record.cid as string }),\n };\n\n if (\n value !== null &&\n typeof value === \"object\" &&\n !Array.isArray(value)\n ) {\n const values: Record<number, number> = {};\n for (const [key, channelValue] of Object.entries(value)) {\n values[Number(key)] = channelValue as number;\n }\n if (sharedDuration !== undefined && sharedDuration > 0) {\n return { mode: \"fade\", values, ...options };\n }\n return { mode: \"set\", values, ...options };\n }\n\n if (!Array.isArray(value)) {\n throw new SacnValidationError(\n \"Body must contain a channels array or map.\",\n \"INVALID_CHANNEL\",\n );\n }\n\n const writes: ChannelWrite[] = value.map((item) => {\n const change = bodyObject(item);\n const durationMs =\n typeof change.durationMs === \"number\" ? change.durationMs : undefined;\n return {\n channel: change.channel as number,\n value: change.value as number,\n ...(durationMs === undefined ? {} : { durationMs }),\n };\n });\n\n const hasPerChannelDuration = writes.some(\n (write) => write.durationMs !== undefined && write.durationMs > 0,\n );\n if (hasPerChannelDuration) {\n return {\n mode: \"transition\",\n writes: writes.map((write) => ({\n channel: write.channel,\n value: write.value,\n durationMs: write.durationMs ?? sharedDuration ?? 0,\n })),\n ...options,\n };\n }\n const values: Record<number, number> = {};\n for (const write of writes) values[write.channel] = write.value;\n if (sharedDuration !== undefined && sharedDuration > 0) {\n return { mode: \"fade\", values, ...options };\n }\n return { mode: \"set\", values, ...options };\n};\n\nconst frameFrom = (\n body: unknown,\n): {\n values: readonly number[] | Uint8Array;\n durationMs?: number;\n idleFps?: number;\n sourceName?: string;\n cid?: string;\n} => {\n const record = bodyObject(body);\n const values = record.values ?? record.initialValues;\n if (!Array.isArray(values) && !(values instanceof Uint8Array)) {\n throw new SacnValidationError(\n \"Body must contain a values array.\",\n \"INVALID_FRAME\",\n );\n }\n const durationMs = record.durationMs;\n return {\n values,\n ...(durationMs === undefined ? {} : { durationMs: durationMs as number }),\n ...(record.idleFps === undefined\n ? {}\n : { idleFps: record.idleFps as number }),\n ...(record.sourceName === undefined\n ? {}\n : { sourceName: record.sourceName as string }),\n ...(record.cid === undefined ? {} : { cid: record.cid as string }),\n };\n};\n\nconst universeOf = (\n source: SacnSourceContract,\n params: OutputParams,\n extras: {\n cid?: string;\n idleFps?: number;\n sourceName?: string;\n } = {},\n): UniverseContract => {\n const address = addressOf(params);\n return source.universe(address.universe, {\n priority: address.priority,\n ...extras,\n });\n};\n\nconst applyChannels = async (\n universe: UniverseContract,\n parsed: ReturnType<typeof channelsFrom>,\n) => {\n if (parsed.mode === \"fade\" && parsed.values) {\n return universe.fadeChannels(parsed.values, {\n durationMs: parsed.durationMs ?? 0,\n });\n }\n if (parsed.mode === \"transition\" && parsed.writes) {\n return universe.transition(parsed.writes);\n }\n if (parsed.values) {\n return universe.setChannels(parsed.values);\n }\n throw new SacnValidationError(\n \"Body must contain channel values.\",\n \"INVALID_CHANNEL\",\n );\n};\n\n/**\n * Creates an unbound Elysia route plugin. CORS and server binding deliberately\n * remain the host application's responsibility.\n */\nexport const createSacnHttpAdapter = (options: SacnHttpAdapterOptions) => {\n const prefix = options.prefix ?? \"/sacn\";\n const sunset = options.sunset ?? \"Wed, 01 Jul 2027 00:00:00 GMT\";\n const maxWebSocketClients = options.maxWebSocketClients ?? 64;\n const webSocketQueueCapacity = options.webSocketQueueCapacity ?? 32;\n if (!Number.isInteger(maxWebSocketClients) || maxWebSocketClients < 1) {\n throw new SacnValidationError(\n \"Maximum WebSocket clients must be a positive integer.\",\n \"INVALID_FRAME\",\n );\n }\n if (!Number.isInteger(webSocketQueueCapacity) || webSocketQueueCapacity < 1) {\n throw new SacnValidationError(\n \"WebSocket queue capacity must be a positive integer.\",\n \"INVALID_FRAME\",\n );\n }\n interface ViewerClient {\n readonly socket: {\n send(payload: unknown): unknown;\n close(): unknown;\n };\n readonly pending: Map<number, ViewerPacket>;\n scheduled: boolean;\n }\n const clients = new Set<ViewerClient>();\n const closeClient = (client: ViewerClient): void => {\n clients.delete(client);\n client.pending.clear();\n try {\n client.socket.close();\n } catch {\n // The client is already discarded.\n }\n };\n const flushClient = (client: ViewerClient): void => {\n client.scheduled = false;\n const packets = [...client.pending.values()];\n client.pending.clear();\n for (const packet of packets) {\n try {\n const status = client.socket.send({ packet, type: \"viewer-packet\" });\n if (typeof status === \"number\" && status <= 0) {\n closeClient(client);\n return;\n }\n } catch {\n closeClient(client);\n return;\n }\n }\n };\n const dispatchViewerPacket = (packet: ViewerPacket): void => {\n try {\n options.onViewerPacket?.(packet);\n } catch {\n // Host packet hooks are isolated from WebSocket fanout.\n }\n for (const client of clients) {\n if (client.pending.has(packet.universe)) {\n client.pending.delete(packet.universe);\n } else if (client.pending.size >= webSocketQueueCapacity) {\n const oldestUniverse = client.pending.keys().next().value;\n if (oldestUniverse !== undefined) client.pending.delete(oldestUniverse);\n }\n client.pending.set(packet.universe, packet);\n if (!client.scheduled) {\n client.scheduled = true;\n queueMicrotask(() => flushClient(client));\n }\n }\n };\n const unsubscribePackets =\n options.viewer\n ? options.viewer.subscribe(dispatchViewerPacket)\n : undefined;\n\n const app = new Elysia({ adapter: node(), prefix })\n .use(\n openapi({\n path: options.openapiPath ?? \"/openapi\",\n documentation: {\n components: {\n schemas: {\n Error: errorSchema as never,\n EngineTelemetry: engineTelemetrySchema as never,\n OutputSnapshot: outputSnapshotSchema as never,\n ViewerState: viewerStateSchema as never,\n ViewerTelemetry: viewerTelemetrySchema as never,\n },\n },\n info: {\n title: \"@helioslx/core sACN API\",\n version: \"0.1.0\",\n },\n },\n }),\n )\n .onBeforeHandle(async ({ request, set }) => {\n try {\n const result = await options.auth?.({ request });\n if (result instanceof Response) return result;\n if (result === false) {\n set.status = 401;\n return { error: \"Unauthorized.\" };\n }\n } catch (error) {\n return fail(set, error);\n }\n })\n .onError(({ code, error, set }) => {\n if (code === \"VALIDATION\") {\n set.status = 400;\n return { error: error.message };\n }\n })\n .onStop(() => {\n unsubscribePackets?.();\n clients.clear();\n })\n .get(\"/health/live\", () => ({ status: \"ok\" as const }), {\n response: { 200: t.Object({ status: t.Literal(\"ok\") }) },\n })\n .get(\n \"/health/ready\",\n ({ set }) => {\n const telemetry = options.source.getTelemetry();\n if (!telemetry.running || telemetry.closed) {\n set.status = 503;\n return { status: \"not-ready\" as const };\n }\n return { status: \"ready\" as const };\n },\n {\n response: {\n 200: t.Object({ status: t.Literal(\"ready\") }),\n 503: t.Object({ status: t.Literal(\"not-ready\") }),\n },\n },\n )\n .get(\"/universes\", async ({ set }) => {\n try {\n return await options.source.listUniverses();\n } catch (error) {\n return fail(set, error);\n }\n }, {\n detail: {\n responses: {\n 200: {\n description: \"Active outputs\",\n content: {\n \"application/json\": {\n schema: {\n type: \"array\",\n items: { $ref: \"#/components/schemas/OutputSnapshot\" },\n },\n },\n },\n },\n 409: errorResponseDocument(\"Lifecycle conflict\"),\n 503: errorResponseDocument(\"Persistence unavailable\"),\n } as never,\n },\n })\n .get(\"/engine/telemetry\", () => options.source.getTelemetry(), {\n detail: {\n responses: componentResponse(\n \"EngineTelemetry\",\n \"Engine telemetry\",\n ) as never,\n },\n })\n .get(\n \"/universes/:universe/priorities/:priority\",\n async ({ params, set }) => {\n try {\n const output = await universeOf(options.source, params).get();\n if (!output) {\n set.status = 404;\n return { error: \"Output not found.\" };\n }\n return output;\n } catch (error) {\n return fail(set, error);\n }\n },\n {\n detail: { responses: outputLookupResponseDocument as never },\n params: outputParamsSchema,\n },\n )\n .put(\n \"/universes/:universe/priorities/:priority\",\n async ({ body, params, set }) => {\n try {\n const record = bodyObject(body);\n const frame = frameFrom({\n ...record,\n values:\n record.initialValues ??\n record.values ??\n Array.from({ length: SLOT_COUNT }, () => 0),\n });\n const universe = universeOf(options.source, params, {\n ...(frame.cid === undefined ? {} : { cid: frame.cid }),\n ...(frame.idleFps === undefined ? {} : { idleFps: frame.idleFps }),\n ...(frame.sourceName === undefined\n ? {}\n : { sourceName: frame.sourceName }),\n });\n const existing = await universe.get();\n const supplied = record.initialValues ?? record.values;\n const values =\n Array.isArray(supplied) || supplied instanceof Uint8Array\n ? supplied\n : existing?.target ?? Array.from({ length: SLOT_COUNT }, () => 0);\n return await universe.write(values, {\n ...(frame.durationMs === undefined\n ? {}\n : { durationMs: frame.durationMs }),\n });\n } catch (error) {\n return fail(set, error);\n }\n },\n {\n body: upsertBodySchema,\n detail: { responses: outputResponseDocument as never },\n params: outputParamsSchema,\n },\n )\n .post(\n \"/universes/:universe/priorities/:priority/channels\",\n async ({ body, params, set }) => {\n try {\n const parsed = channelsFrom(body);\n const universe = universeOf(options.source, params, {\n ...(parsed.cid === undefined ? {} : { cid: parsed.cid }),\n ...(parsed.idleFps === undefined ? {} : { idleFps: parsed.idleFps }),\n ...(parsed.sourceName === undefined\n ? {}\n : { sourceName: parsed.sourceName }),\n });\n return await applyChannels(universe, parsed);\n } catch (error) {\n return fail(set, error);\n }\n },\n {\n body: channelsBodySchema,\n detail: { responses: outputResponseDocument as never },\n params: outputParamsSchema,\n },\n )\n .post(\n \"/universes/:universe/priorities/:priority/frame\",\n async ({ body, params, set }) => {\n try {\n const frame = frameFrom(body);\n const universe = universeOf(options.source, params, {\n ...(frame.cid === undefined ? {} : { cid: frame.cid }),\n ...(frame.idleFps === undefined ? {} : { idleFps: frame.idleFps }),\n ...(frame.sourceName === undefined\n ? {}\n : { sourceName: frame.sourceName }),\n });\n return await universe.write(frame.values, {\n ...(frame.durationMs === undefined\n ? {}\n : { durationMs: frame.durationMs }),\n });\n } catch (error) {\n return fail(set, error);\n }\n },\n {\n body: frameBodySchema,\n detail: { responses: outputResponseDocument as never },\n params: outputParamsSchema,\n },\n )\n .delete(\n \"/universes/:universe/priorities/:priority\",\n async ({ params, set }) => {\n try {\n const removed = await universeOf(options.source, params).clear();\n if (!removed) {\n set.status = 404;\n return { error: \"Output not found.\" };\n }\n return { ok: true as const };\n } catch (error) {\n return fail(set, error);\n }\n },\n {\n detail: {\n responses: {\n 200: {\n description: \"Output cleared\",\n content: {\n \"application/json\": {\n schema: {\n type: \"object\",\n required: [\"ok\"],\n properties: { ok: { type: \"boolean\", const: true } },\n },\n },\n },\n },\n 400: errorResponseDocument(\"Invalid request\"),\n 404: errorResponseDocument(\"Output not found\"),\n 409: errorResponseDocument(\"Lifecycle conflict\"),\n 503: errorResponseDocument(\"Transport or persistence unavailable\"),\n } as never,\n },\n params: outputParamsSchema,\n },\n );\n\n if (options.viewer) {\n app\n .get(\"/viewer/universes\", () => ({\n universes: options.viewer?.getSelectedUniverses() ?? [],\n }), {\n detail: {\n responses: componentResponse(\n \"ViewerState\",\n \"Selected viewer universes\",\n ) as never,\n },\n })\n .get(\"/viewer/telemetry\", () => options.viewer?.getTelemetry(), {\n detail: {\n responses: componentResponse(\n \"ViewerTelemetry\",\n \"Viewer telemetry\",\n ) as never,\n },\n })\n .put(\n \"/viewer/universes\",\n async ({ body, set }) => {\n try {\n const record = bodyObject(body);\n if (!Array.isArray(record.universes)) {\n throw new SacnValidationError(\n \"Body must contain a universes array.\",\n \"INVALID_UNIVERSE\",\n );\n }\n return {\n universes: await options.viewer?.setSelectedUniverses(\n record.universes as number[],\n ),\n };\n } catch (error) {\n return fail(set, error);\n }\n },\n {\n body: viewerStateSchema,\n detail: {\n responses: componentResponse(\n \"ViewerState\",\n \"Updated viewer universes\",\n ) as never,\n },\n },\n )\n .post(\n \"/viewer/universes/:universe\",\n async ({ params, set }) => {\n try {\n return {\n universes: await options.viewer?.addUniverse(\n integerParam(params.universe, \"Universe\"),\n ),\n };\n } catch (error) {\n return fail(set, error);\n }\n },\n {\n detail: {\n responses: componentResponse(\n \"ViewerState\",\n \"Updated viewer universes\",\n ) as never,\n },\n params: viewerUniverseParamsSchema,\n },\n )\n .delete(\n \"/viewer/universes/:universe\",\n async ({ params, set }) => {\n try {\n return {\n universes: await options.viewer?.removeUniverse(\n integerParam(params.universe, \"Universe\"),\n ),\n };\n } catch (error) {\n return fail(set, error);\n }\n },\n {\n detail: {\n responses: componentResponse(\n \"ViewerState\",\n \"Updated viewer universes\",\n ) as never,\n },\n params: viewerUniverseParamsSchema,\n },\n )\n .delete(\n \"/viewer/universes\",\n async ({ set }) => {\n try {\n return {\n universes: await options.viewer?.setSelectedUniverses([]),\n };\n } catch (error) {\n return fail(set, error);\n }\n },\n {\n detail: {\n responses: componentResponse(\n \"ViewerState\",\n \"Cleared viewer universes\",\n ) as never,\n },\n },\n )\n .ws(\"/viewer/ws\", {\n open(ws) {\n if (clients.size >= maxWebSocketClients) {\n ws.close();\n return;\n }\n const client: ViewerClient = {\n socket: ws,\n pending: new Map(),\n scheduled: false,\n };\n clients.add(client);\n ws.send({\n type: \"viewer-state\",\n viewer: {\n universes: options.viewer?.getSelectedUniverses() ?? [],\n },\n });\n },\n close(ws) {\n for (const client of clients) {\n if (client.socket === ws) {\n clients.delete(client);\n client.pending.clear();\n break;\n }\n }\n },\n message() {\n // Viewer sockets are intentionally server-to-client only.\n },\n });\n }\n\n const mark = (set: RouteSet, successor: string): void =>\n deprecated(set, `${prefix}${successor}`, sunset);\n\n return app\n .get(\"/outputs\", async ({ set }) => {\n mark(set, \"/universes\");\n try {\n return await options.source.listUniverses();\n } catch (error) {\n return fail(set, error);\n }\n }, {\n detail: {\n deprecated: true,\n responses: {\n 200: {\n description: \"Active outputs\",\n content: {\n \"application/json\": {\n schema: {\n type: \"array\",\n items: { $ref: \"#/components/schemas/OutputSnapshot\" },\n },\n },\n },\n },\n } as never,\n },\n })\n .get(\"/telemetry\", ({ set }) => {\n mark(set, \"/engine/telemetry\");\n return options.source.getTelemetry();\n }, {\n detail: {\n deprecated: true,\n responses: componentResponse(\n \"EngineTelemetry\",\n \"Engine telemetry\",\n ) as never,\n },\n })\n .get(\n \"/outputs/:universe/:priority\",\n async ({ params, set }) => {\n mark(\n set,\n `/universes/${params.universe}/priorities/${params.priority}`,\n );\n try {\n const output = await universeOf(options.source, params).get();\n if (!output) {\n set.status = 404;\n return { error: \"Output not found.\" };\n }\n return output;\n } catch (error) {\n return fail(set, error);\n }\n },\n {\n detail: {\n deprecated: true,\n responses: outputLookupResponseDocument as never,\n },\n params: outputParamsSchema,\n },\n )\n .put(\n \"/outputs/:universe/:priority\",\n async ({ body, params, set }) => {\n mark(\n set,\n `/universes/${params.universe}/priorities/${params.priority}`,\n );\n try {\n const record = bodyObject(body);\n const frame = frameFrom({\n ...record,\n values:\n record.initialValues ??\n record.values ??\n Array.from({ length: SLOT_COUNT }, () => 0),\n });\n const universe = universeOf(options.source, params, {\n ...(frame.cid === undefined ? {} : { cid: frame.cid }),\n ...(frame.idleFps === undefined ? {} : { idleFps: frame.idleFps }),\n ...(frame.sourceName === undefined\n ? {}\n : { sourceName: frame.sourceName }),\n });\n const existing = await universe.get();\n const supplied = record.initialValues ?? record.values;\n const values =\n Array.isArray(supplied) || supplied instanceof Uint8Array\n ? supplied\n : existing?.target ?? Array.from({ length: SLOT_COUNT }, () => 0);\n return await universe.write(values, {\n ...(frame.durationMs === undefined\n ? {}\n : { durationMs: frame.durationMs }),\n });\n } catch (error) {\n return fail(set, error);\n }\n },\n {\n body: upsertBodySchema,\n detail: {\n deprecated: true,\n responses: outputResponseDocument as never,\n },\n params: outputParamsSchema,\n },\n )\n .post(\n \"/outputs/:universe/:priority/channels\",\n async ({ body, params, set }) => {\n mark(\n set,\n `/universes/${params.universe}/priorities/${params.priority}/channels`,\n );\n try {\n const parsed = channelsFrom(body);\n const universe = universeOf(options.source, params, {\n ...(parsed.cid === undefined ? {} : { cid: parsed.cid }),\n ...(parsed.idleFps === undefined ? {} : { idleFps: parsed.idleFps }),\n ...(parsed.sourceName === undefined\n ? {}\n : { sourceName: parsed.sourceName }),\n });\n return await applyChannels(universe, parsed);\n } catch (error) {\n return fail(set, error);\n }\n },\n {\n body: channelsBodySchema,\n detail: {\n deprecated: true,\n responses: outputResponseDocument as never,\n },\n params: outputParamsSchema,\n },\n )\n .post(\n \"/outputs/:universe/:priority/frame\",\n async ({ body, params, set }) => {\n mark(\n set,\n `/universes/${params.universe}/priorities/${params.priority}/frame`,\n );\n try {\n const frame = frameFrom(body);\n const universe = universeOf(options.source, params, {\n ...(frame.cid === undefined ? {} : { cid: frame.cid }),\n ...(frame.idleFps === undefined ? {} : { idleFps: frame.idleFps }),\n ...(frame.sourceName === undefined\n ? {}\n : { sourceName: frame.sourceName }),\n });\n return await universe.write(frame.values, {\n ...(frame.durationMs === undefined\n ? {}\n : { durationMs: frame.durationMs }),\n });\n } catch (error) {\n return fail(set, error);\n }\n },\n {\n body: frameBodySchema,\n detail: {\n deprecated: true,\n responses: outputResponseDocument as never,\n },\n params: outputParamsSchema,\n },\n )\n .delete(\n \"/outputs/:universe/:priority\",\n async ({ params, set }) => {\n mark(\n set,\n `/universes/${params.universe}/priorities/${params.priority}`,\n );\n try {\n const removed = await universeOf(options.source, params).clear();\n if (!removed) {\n set.status = 404;\n return { error: \"Output not found.\" };\n }\n return { ok: true as const };\n } catch (error) {\n return fail(set, error);\n }\n },\n {\n detail: {\n deprecated: true,\n responses: clearResponseDocument as never,\n },\n params: outputParamsSchema,\n },\n );\n};\n\n/** Connects viewer packets to a host-owned WebSocket or SSE implementation. */\nexport const subscribeViewerPackets = (\n viewer: ViewerServiceContract,\n listener: (packet: ViewerPacket) => void,\n): (() => void) => viewer.subscribe(listener);\n"],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { A as SacnSourceOptions, B as ViewerSourceMetadata, C as Receiver, D as SacnLifecycleHook, E as SLOT_COUNT, F as ViewerPacket, H as ViewerTelemetry, I as ViewerPacketStream, L as ViewerRecord, M as TransportTelemetry, N as UniverseContract, O as SacnSourceContract, P as UniverseOptions, R as ViewerServiceContract, S as OutputTransport, T as ReceiverPacketListener, U as WriteFrameOptions, V as ViewerStore, _ as OutputOptions, a as DEFAULT_ACTIVE_FPS, b as OutputSnapshot, c as EngineTelemetry, d as Logger, f as MAX_PRIORITY, g as OutputAddress, h as MIN_UNIVERSE, i as Clock, j as TransitionWrite, k as SacnSourceEvent, l as FadeChannelsOptions, m as MIN_PRIORITY, n as ChannelWrite, o as DEFAULT_IDLE_FPS, p as MAX_UNIVERSE, r as ClearUniverseOptions, s as DEFAULT_PRIORITY, t as ChannelValues, u as FrameMode, v as OutputPacket, w as ReceiverPacket, x as OutputStore, y as OutputRecord, z as ViewerServiceOptions } from "./contracts-C4kpAdZq.js";
|
|
2
|
+
import { a as PersistenceError, c as SacnValidationError, d as ValidationCode, i as DependencyUnavailableError, l as TransportError, n as Universe, o as SacnError, r as createSacnSource, s as SacnLifecycleError, t as SacnSource, u as TransportTimeoutError } from "./source-D_XNWXS9.js";
|
|
3
|
+
//#region src/memory-store.d.ts
|
|
4
|
+
declare class MemoryOutputStore implements OutputStore {
|
|
5
|
+
#private;
|
|
6
|
+
get(address: Required<OutputAddress>): Promise<OutputRecord | null>;
|
|
7
|
+
list(): Promise<readonly OutputRecord[]>;
|
|
8
|
+
remove(address: Required<OutputAddress>): Promise<void>;
|
|
9
|
+
save(record: OutputRecord): Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
//#endregion
|
|
12
|
+
//#region src/viewer.d.ts
|
|
13
|
+
declare class ViewerService implements ViewerServiceContract {
|
|
14
|
+
#private;
|
|
15
|
+
constructor(options: ViewerServiceOptions);
|
|
16
|
+
start(): Promise<void>;
|
|
17
|
+
getSelectedUniverses(): readonly number[];
|
|
18
|
+
setSelectedUniverses(universes: readonly number[]): Promise<readonly number[]>;
|
|
19
|
+
addUniverse(universe: number): Promise<readonly number[]>;
|
|
20
|
+
removeUniverse(universe: number): Promise<readonly number[]>;
|
|
21
|
+
subscribe(listener: (packet: ViewerPacket) => void): () => void;
|
|
22
|
+
packets(capacity?: number): ViewerPacketStream;
|
|
23
|
+
getTelemetry(): ViewerTelemetry;
|
|
24
|
+
close(): Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
declare class MemoryViewerStore implements ViewerStore {
|
|
27
|
+
#private;
|
|
28
|
+
load(): Promise<ViewerRecord | null>;
|
|
29
|
+
save(record: ViewerRecord): Promise<void>;
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
//#region src/output-engine.d.ts
|
|
33
|
+
declare class SystemClock implements Clock {
|
|
34
|
+
now(): number;
|
|
35
|
+
wallNow(): number;
|
|
36
|
+
sleep(delayMs: number, signal: AbortSignal): Promise<void>;
|
|
37
|
+
}
|
|
38
|
+
//#endregion
|
|
39
|
+
export { type ChannelValues, type ChannelWrite, type ClearUniverseOptions, type Clock, DEFAULT_ACTIVE_FPS, DEFAULT_IDLE_FPS, DEFAULT_PRIORITY, DependencyUnavailableError, type EngineTelemetry, type FadeChannelsOptions, type FrameMode, type Logger, MAX_PRIORITY, MAX_UNIVERSE, MIN_PRIORITY, MIN_UNIVERSE, MemoryOutputStore, MemoryViewerStore, type OutputAddress, type OutputOptions, type OutputPacket, type OutputRecord, type OutputSnapshot, type OutputStore, type OutputTransport, PersistenceError, type Receiver, type ReceiverPacket, type ReceiverPacketListener, SLOT_COUNT, SacnError, SacnLifecycleError, type SacnLifecycleHook, SacnSource, type SacnSourceContract, type SacnSourceEvent, type SacnSourceOptions, SacnValidationError, SystemClock, type TransitionWrite, TransportError, type TransportTelemetry, TransportTimeoutError, Universe, type UniverseContract, type UniverseOptions, type ValidationCode, type ViewerPacket, type ViewerPacketStream, type ViewerRecord, ViewerService, type ViewerServiceContract, type ViewerServiceOptions, type ViewerSourceMetadata, type ViewerStore, type ViewerTelemetry, type WriteFrameOptions, createSacnSource };
|
|
40
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/memory-store.ts","../src/viewer.ts","../src/output-engine.ts"],"mappings":";;;cAea,6BAA6B;;EAGlC,IAAI,SAAS,SAAS,iBAAiB,QAAQ;EAK/C,QAAQ,iBAAiB;EAWzB,OAAO,SAAS,SAAS,iBAAiB;EAI1C,KAAK,QAAQ,eAAe;;;;cCoFvB,yBAAyB;;EAoBpC,YAAY,SAAS;EA4Bf,SAAS;EASf;EAIA,qBAAqB,+BAA+B;EAOpD,YAAY,mBAAmB;EAI/B,eAAe,mBAAmB;EAIlC,UAAU,WAAW,QAAQ;EAO7B,QAAQ,oBAAkC;EAkB1C,gBAAgB;EASV,SAAS;;cA6HJ,6BAA6B;;EAGlC,QAAQ,QAAQ;EAIhB,KAAK,QAAQ,eAAe;;;;cCnRvB,uBAAuB;EAClC;EAIA;EAIA,MAAM,iBAAiB,QAAQ,cAAc"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import { C as MAX_UNIVERSE, E as SLOT_COUNT, S as MAX_PRIORITY, T as MIN_UNIVERSE, a as SacnValidationError, b as DEFAULT_IDLE_FPS, i as SacnLifecycleError, n as PersistenceError, o as TransportError, r as SacnError, s as TransportTimeoutError, t as DependencyUnavailableError, w as MIN_PRIORITY, x as DEFAULT_PRIORITY, y as DEFAULT_ACTIVE_FPS } from "./validation-BdsVeyAE.js";
|
|
2
|
+
import { a as MemoryOutputStore, i as SystemClock, n as Universe, r as createSacnSource, t as SacnSource } from "./source-DB1oq2GT.js";
|
|
3
|
+
//#region src/viewer.ts
|
|
4
|
+
const normalizeUniverses = (universes, maximum) => {
|
|
5
|
+
const unique = [...new Set(universes)];
|
|
6
|
+
for (const universe of unique) if (!Number.isInteger(universe) || universe < 1 || universe > 63999) throw new SacnValidationError(`Universe must be an integer between 1 and ${MAX_UNIVERSE}.`, "INVALID_UNIVERSE");
|
|
7
|
+
if (unique.length > maximum) throw new SacnValidationError(`At most ${maximum} viewer universes may be selected.`, "INVALID_UNIVERSE");
|
|
8
|
+
return Object.freeze(unique.sort((left, right) => left - right));
|
|
9
|
+
};
|
|
10
|
+
const normalizePacket = (packet, receivedAt) => {
|
|
11
|
+
const values = Array.from({ length: 512 }, (_, index) => packet.values[index] ?? 0);
|
|
12
|
+
return Object.freeze({
|
|
13
|
+
universe: packet.universe,
|
|
14
|
+
receivedAt,
|
|
15
|
+
values: Object.freeze(values),
|
|
16
|
+
source: Object.freeze({
|
|
17
|
+
cid: packet.cid,
|
|
18
|
+
priority: packet.priority,
|
|
19
|
+
sequence: packet.sequence,
|
|
20
|
+
sourceAddress: packet.sourceAddress,
|
|
21
|
+
sourceName: packet.sourceName
|
|
22
|
+
})
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
var PacketStream = class {
|
|
26
|
+
#capacity;
|
|
27
|
+
#onDrop;
|
|
28
|
+
#onClose;
|
|
29
|
+
#queue = [];
|
|
30
|
+
#waiting = [];
|
|
31
|
+
#closed = false;
|
|
32
|
+
constructor(capacity, onDrop, onClose) {
|
|
33
|
+
this.#capacity = capacity;
|
|
34
|
+
this.#onDrop = onDrop;
|
|
35
|
+
this.#onClose = onClose;
|
|
36
|
+
}
|
|
37
|
+
push(packet) {
|
|
38
|
+
if (this.#closed) return;
|
|
39
|
+
const resolve = this.#waiting.shift();
|
|
40
|
+
if (resolve) {
|
|
41
|
+
resolve({
|
|
42
|
+
value: packet,
|
|
43
|
+
done: false
|
|
44
|
+
});
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const existing = this.#queue.findIndex((queued) => queued.universe === packet.universe);
|
|
48
|
+
if (existing >= 0) {
|
|
49
|
+
this.#queue.splice(existing, 1);
|
|
50
|
+
this.#onDrop();
|
|
51
|
+
} else if (this.#queue.length >= this.#capacity) {
|
|
52
|
+
this.#queue.shift();
|
|
53
|
+
this.#onDrop();
|
|
54
|
+
}
|
|
55
|
+
this.#queue.push(packet);
|
|
56
|
+
}
|
|
57
|
+
close() {
|
|
58
|
+
if (this.#closed) return;
|
|
59
|
+
this.#closed = true;
|
|
60
|
+
this.#queue.length = 0;
|
|
61
|
+
for (const resolve of this.#waiting.splice(0)) resolve({
|
|
62
|
+
value: void 0,
|
|
63
|
+
done: true
|
|
64
|
+
});
|
|
65
|
+
this.#onClose();
|
|
66
|
+
}
|
|
67
|
+
[Symbol.asyncIterator]() {
|
|
68
|
+
return {
|
|
69
|
+
next: async () => {
|
|
70
|
+
const packet = this.#queue.shift();
|
|
71
|
+
if (packet) return {
|
|
72
|
+
value: packet,
|
|
73
|
+
done: false
|
|
74
|
+
};
|
|
75
|
+
if (this.#closed) return {
|
|
76
|
+
value: void 0,
|
|
77
|
+
done: true
|
|
78
|
+
};
|
|
79
|
+
return await new Promise((resolve) => {
|
|
80
|
+
this.#waiting.push(resolve);
|
|
81
|
+
});
|
|
82
|
+
},
|
|
83
|
+
return: async () => {
|
|
84
|
+
this.close();
|
|
85
|
+
return {
|
|
86
|
+
value: void 0,
|
|
87
|
+
done: true
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
var ViewerService = class {
|
|
94
|
+
#receiver;
|
|
95
|
+
#store;
|
|
96
|
+
#clock;
|
|
97
|
+
#logger;
|
|
98
|
+
#ownsReceiver;
|
|
99
|
+
#ownsStore;
|
|
100
|
+
#streamCapacity;
|
|
101
|
+
#maxUniverses;
|
|
102
|
+
#maxListeners;
|
|
103
|
+
#listeners = /* @__PURE__ */ new Set();
|
|
104
|
+
#streams = /* @__PURE__ */ new Set();
|
|
105
|
+
#unsubscribe;
|
|
106
|
+
#selected = Object.freeze([]);
|
|
107
|
+
#queue = Promise.resolve();
|
|
108
|
+
#started = false;
|
|
109
|
+
#closed = false;
|
|
110
|
+
#packetsReceived = 0;
|
|
111
|
+
#droppedUpdates = 0;
|
|
112
|
+
constructor(options) {
|
|
113
|
+
this.#receiver = options.receiver;
|
|
114
|
+
this.#store = options.store ?? new MemoryViewerStore();
|
|
115
|
+
this.#clock = options.clock ?? { now: () => Date.now() };
|
|
116
|
+
this.#logger = options.logger ?? {};
|
|
117
|
+
this.#ownsReceiver = options.ownsReceiver ?? false;
|
|
118
|
+
this.#ownsStore = options.ownsStore ?? options.store === void 0;
|
|
119
|
+
this.#streamCapacity = options.streamCapacity ?? 32;
|
|
120
|
+
this.#maxUniverses = options.maxUniverses ?? 256;
|
|
121
|
+
this.#maxListeners = options.maxListeners ?? 256;
|
|
122
|
+
if (!Number.isInteger(this.#streamCapacity) || this.#streamCapacity < 1) throw new SacnValidationError("Stream capacity must be a positive integer.", "INVALID_FRAME");
|
|
123
|
+
if (!Number.isInteger(this.#maxUniverses) || this.#maxUniverses < 1) throw new SacnValidationError("Maximum universes must be a positive integer.", "INVALID_UNIVERSE");
|
|
124
|
+
if (!Number.isInteger(this.#maxListeners) || this.#maxListeners < 1) throw new SacnValidationError("Maximum listeners must be a positive integer.", "INVALID_FRAME");
|
|
125
|
+
this.#unsubscribe = this.#receiver.subscribe((packet) => this.#receive(packet));
|
|
126
|
+
}
|
|
127
|
+
async start() {
|
|
128
|
+
await this.#enqueue(async () => {
|
|
129
|
+
if (this.#started) return;
|
|
130
|
+
const record = await this.#persist("load viewer state", () => this.#store.load());
|
|
131
|
+
if (record) await this.#applyUniverses(record.selectedUniverses, false);
|
|
132
|
+
this.#started = true;
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
getSelectedUniverses() {
|
|
136
|
+
return this.#selected;
|
|
137
|
+
}
|
|
138
|
+
setSelectedUniverses(universes) {
|
|
139
|
+
return this.#enqueue(async () => {
|
|
140
|
+
await this.#applyUniverses(universes, true);
|
|
141
|
+
return this.#selected;
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
addUniverse(universe) {
|
|
145
|
+
return this.setSelectedUniverses([...this.#selected, universe]);
|
|
146
|
+
}
|
|
147
|
+
removeUniverse(universe) {
|
|
148
|
+
return this.setSelectedUniverses(this.#selected.filter((item) => item !== universe));
|
|
149
|
+
}
|
|
150
|
+
subscribe(listener) {
|
|
151
|
+
this.#assertOpen();
|
|
152
|
+
this.#assertListenerCapacity();
|
|
153
|
+
this.#listeners.add(listener);
|
|
154
|
+
return () => this.#listeners.delete(listener);
|
|
155
|
+
}
|
|
156
|
+
packets(capacity = this.#streamCapacity) {
|
|
157
|
+
this.#assertOpen();
|
|
158
|
+
this.#assertListenerCapacity();
|
|
159
|
+
if (!Number.isInteger(capacity) || capacity < 1) throw new SacnValidationError("Stream capacity must be a positive integer.", "INVALID_FRAME");
|
|
160
|
+
let stream;
|
|
161
|
+
stream = new PacketStream(capacity, () => {
|
|
162
|
+
this.#droppedUpdates += 1;
|
|
163
|
+
}, () => this.#streams.delete(stream));
|
|
164
|
+
this.#streams.add(stream);
|
|
165
|
+
return stream;
|
|
166
|
+
}
|
|
167
|
+
getTelemetry() {
|
|
168
|
+
return Object.freeze({
|
|
169
|
+
selectedUniverses: this.#selected,
|
|
170
|
+
packetsReceived: this.#packetsReceived,
|
|
171
|
+
droppedUpdates: this.#droppedUpdates,
|
|
172
|
+
streamCount: this.#streams.size
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
async close() {
|
|
176
|
+
if (this.#closed) return;
|
|
177
|
+
this.#closed = true;
|
|
178
|
+
await this.#queue;
|
|
179
|
+
this.#unsubscribe();
|
|
180
|
+
for (const stream of [...this.#streams]) stream.close();
|
|
181
|
+
this.#listeners.clear();
|
|
182
|
+
const errors = [];
|
|
183
|
+
if (this.#ownsReceiver) try {
|
|
184
|
+
await this.#receiver.close();
|
|
185
|
+
} catch (error) {
|
|
186
|
+
errors.push(error);
|
|
187
|
+
}
|
|
188
|
+
if (this.#ownsStore) try {
|
|
189
|
+
await this.#persist("close viewer store", async () => {
|
|
190
|
+
await this.#store.close?.();
|
|
191
|
+
});
|
|
192
|
+
} catch (error) {
|
|
193
|
+
errors.push(error);
|
|
194
|
+
}
|
|
195
|
+
if (errors.length === 1) throw errors[0];
|
|
196
|
+
if (errors.length > 1) throw new AggregateError(errors, "Viewer shutdown failed.");
|
|
197
|
+
}
|
|
198
|
+
async #applyUniverses(universes, save) {
|
|
199
|
+
const next = normalizeUniverses(universes, this.#maxUniverses);
|
|
200
|
+
const previousSelection = this.#selected;
|
|
201
|
+
const previous = new Set(previousSelection);
|
|
202
|
+
const desired = new Set(next);
|
|
203
|
+
try {
|
|
204
|
+
for (const universe of previousSelection) if (!desired.has(universe)) await this.#receiver.removeUniverse(universe);
|
|
205
|
+
for (const universe of next) if (!previous.has(universe)) await this.#receiver.addUniverse(universe);
|
|
206
|
+
this.#selected = next;
|
|
207
|
+
if (save) await this.#persist("save viewer state", () => this.#store.save({
|
|
208
|
+
selectedUniverses: next,
|
|
209
|
+
updatedAt: this.#clock.now()
|
|
210
|
+
}));
|
|
211
|
+
} catch (error) {
|
|
212
|
+
try {
|
|
213
|
+
for (const universe of next) if (!previous.has(universe)) await this.#receiver.removeUniverse(universe);
|
|
214
|
+
for (const universe of previousSelection) if (!desired.has(universe)) await this.#receiver.addUniverse(universe);
|
|
215
|
+
this.#selected = previousSelection;
|
|
216
|
+
} catch (rollbackError) {
|
|
217
|
+
throw new AggregateError([error, rollbackError], "Viewer universe update and rollback failed.");
|
|
218
|
+
}
|
|
219
|
+
throw error;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
#receive(packet) {
|
|
223
|
+
if (this.#closed || !this.#selected.includes(packet.universe)) return;
|
|
224
|
+
const normalized = normalizePacket(packet, this.#clock.now());
|
|
225
|
+
this.#packetsReceived += 1;
|
|
226
|
+
for (const listener of this.#listeners) try {
|
|
227
|
+
listener(normalized);
|
|
228
|
+
} catch (error) {
|
|
229
|
+
this.#logger.warn?.("Viewer packet listener failed.", { error });
|
|
230
|
+
}
|
|
231
|
+
for (const stream of this.#streams) stream.push(normalized);
|
|
232
|
+
}
|
|
233
|
+
#enqueue(operation) {
|
|
234
|
+
if (this.#closed) return Promise.reject(new SacnLifecycleError("Viewer service is closed."));
|
|
235
|
+
const result = this.#queue.then(operation);
|
|
236
|
+
this.#queue = result.then(() => void 0, () => void 0);
|
|
237
|
+
return result;
|
|
238
|
+
}
|
|
239
|
+
async #persist(action, operation) {
|
|
240
|
+
try {
|
|
241
|
+
return await operation();
|
|
242
|
+
} catch (error) {
|
|
243
|
+
if (error instanceof PersistenceError) throw error;
|
|
244
|
+
throw new PersistenceError(`Failed to ${action}.`, error);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
#assertOpen() {
|
|
248
|
+
if (this.#closed) throw new SacnLifecycleError("Viewer service is closed.");
|
|
249
|
+
}
|
|
250
|
+
#assertListenerCapacity() {
|
|
251
|
+
if (this.#listeners.size + this.#streams.size >= this.#maxListeners) throw new SacnLifecycleError(`Viewer subscriber limit of ${this.#maxListeners} has been reached.`);
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
const cloneRecord = (record) => Object.freeze({
|
|
255
|
+
selectedUniverses: Object.freeze([...record.selectedUniverses]),
|
|
256
|
+
updatedAt: record.updatedAt
|
|
257
|
+
});
|
|
258
|
+
var MemoryViewerStore = class {
|
|
259
|
+
#record = null;
|
|
260
|
+
async load() {
|
|
261
|
+
return this.#record ? cloneRecord(this.#record) : null;
|
|
262
|
+
}
|
|
263
|
+
async save(record) {
|
|
264
|
+
this.#record = cloneRecord(record);
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
//#endregion
|
|
268
|
+
export { DEFAULT_ACTIVE_FPS, DEFAULT_IDLE_FPS, DEFAULT_PRIORITY, DependencyUnavailableError, MAX_PRIORITY, MAX_UNIVERSE, MIN_PRIORITY, MIN_UNIVERSE, MemoryOutputStore, MemoryViewerStore, PersistenceError, SLOT_COUNT, SacnError, SacnLifecycleError, SacnSource, SacnValidationError, SystemClock, TransportError, TransportTimeoutError, Universe, ViewerService, createSacnSource };
|
|
269
|
+
|
|
270
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["#capacity","#onDrop","#onClose","#queue","#waiting","#closed","#receiver","#store","#clock","#logger","#ownsReceiver","#ownsStore","#streamCapacity","#maxUniverses","#maxListeners","#listeners","#streams","#unsubscribe","#receive","#enqueue","#started","#persist","#applyUniverses","#selected","#assertOpen","#assertListenerCapacity","#droppedUpdates","#packetsReceived","#record"],"sources":["../src/viewer.ts"],"sourcesContent":["import {\n MAX_UNIVERSE,\n MIN_UNIVERSE,\n SLOT_COUNT,\n type Logger,\n type ReceiverPacket,\n type ViewerPacket,\n type ViewerPacketStream,\n type ViewerRecord,\n type ViewerServiceContract,\n type ViewerServiceOptions,\n type ViewerStore,\n type ViewerTelemetry,\n} from \"./contracts.js\";\nimport { PersistenceError, SacnLifecycleError, SacnValidationError } from \"./validation.js\";\n\nconst normalizeUniverses = (\n universes: readonly number[],\n maximum: number,\n): readonly number[] => {\n const unique = [...new Set(universes)];\n for (const universe of unique) {\n if (\n !Number.isInteger(universe) ||\n universe < MIN_UNIVERSE ||\n universe > MAX_UNIVERSE\n ) {\n throw new SacnValidationError(\n `Universe must be an integer between ${MIN_UNIVERSE} and ${MAX_UNIVERSE}.`,\n \"INVALID_UNIVERSE\",\n );\n }\n }\n if (unique.length > maximum) {\n throw new SacnValidationError(\n `At most ${maximum} viewer universes may be selected.`,\n \"INVALID_UNIVERSE\",\n );\n }\n return Object.freeze(unique.sort((left, right) => left - right));\n};\n\nconst normalizePacket = (packet: ReceiverPacket, receivedAt: number): ViewerPacket => {\n const values = Array.from({ length: SLOT_COUNT }, (_, index) => packet.values[index] ?? 0);\n return Object.freeze({\n universe: packet.universe,\n receivedAt,\n values: Object.freeze(values),\n source: Object.freeze({\n cid: packet.cid,\n priority: packet.priority,\n sequence: packet.sequence,\n sourceAddress: packet.sourceAddress,\n sourceName: packet.sourceName,\n }),\n });\n};\n\nclass PacketStream implements ViewerPacketStream {\n readonly #capacity: number;\n readonly #onDrop: () => void;\n readonly #onClose: () => void;\n readonly #queue: ViewerPacket[] = [];\n readonly #waiting: Array<\n (result: IteratorResult<ViewerPacket>) => void\n > = [];\n #closed = false;\n\n constructor(capacity: number, onDrop: () => void, onClose: () => void) {\n this.#capacity = capacity;\n this.#onDrop = onDrop;\n this.#onClose = onClose;\n }\n\n push(packet: ViewerPacket): void {\n if (this.#closed) return;\n const resolve = this.#waiting.shift();\n if (resolve) {\n resolve({ value: packet, done: false });\n return;\n }\n const existing = this.#queue.findIndex(\n (queued) => queued.universe === packet.universe,\n );\n if (existing >= 0) {\n this.#queue.splice(existing, 1);\n this.#onDrop();\n } else if (this.#queue.length >= this.#capacity) {\n this.#queue.shift();\n this.#onDrop();\n }\n this.#queue.push(packet);\n }\n\n close(): void {\n if (this.#closed) return;\n this.#closed = true;\n this.#queue.length = 0;\n for (const resolve of this.#waiting.splice(0)) {\n resolve({ value: undefined, done: true });\n }\n this.#onClose();\n }\n\n [Symbol.asyncIterator](): AsyncIterator<ViewerPacket> {\n return {\n next: async () => {\n const packet = this.#queue.shift();\n if (packet) return { value: packet, done: false };\n if (this.#closed) return { value: undefined, done: true };\n return await new Promise<IteratorResult<ViewerPacket>>((resolve) => {\n this.#waiting.push(resolve);\n });\n },\n return: async () => {\n this.close();\n return { value: undefined, done: true };\n },\n };\n }\n}\n\nexport class ViewerService implements ViewerServiceContract {\n readonly #receiver: ViewerServiceOptions[\"receiver\"];\n readonly #store: ViewerStore;\n readonly #clock: NonNullable<ViewerServiceOptions[\"clock\"]>;\n readonly #logger: Logger;\n readonly #ownsReceiver: boolean;\n readonly #ownsStore: boolean;\n readonly #streamCapacity: number;\n readonly #maxUniverses: number;\n readonly #maxListeners: number;\n readonly #listeners = new Set<(packet: ViewerPacket) => void>();\n readonly #streams = new Set<PacketStream>();\n readonly #unsubscribe: () => void;\n #selected: readonly number[] = Object.freeze([]);\n #queue: Promise<void> = Promise.resolve();\n #started = false;\n #closed = false;\n #packetsReceived = 0;\n #droppedUpdates = 0;\n\n constructor(options: ViewerServiceOptions) {\n this.#receiver = options.receiver;\n this.#store = options.store ?? new MemoryViewerStore();\n this.#clock = options.clock ?? { now: () => Date.now() };\n this.#logger = options.logger ?? {};\n this.#ownsReceiver = options.ownsReceiver ?? false;\n this.#ownsStore = options.ownsStore ?? options.store === undefined;\n this.#streamCapacity = options.streamCapacity ?? 32;\n this.#maxUniverses = options.maxUniverses ?? 256;\n this.#maxListeners = options.maxListeners ?? 256;\n if (!Number.isInteger(this.#streamCapacity) || this.#streamCapacity < 1) {\n throw new SacnValidationError(\"Stream capacity must be a positive integer.\", \"INVALID_FRAME\");\n }\n if (!Number.isInteger(this.#maxUniverses) || this.#maxUniverses < 1) {\n throw new SacnValidationError(\n \"Maximum universes must be a positive integer.\",\n \"INVALID_UNIVERSE\",\n );\n }\n if (!Number.isInteger(this.#maxListeners) || this.#maxListeners < 1) {\n throw new SacnValidationError(\n \"Maximum listeners must be a positive integer.\",\n \"INVALID_FRAME\",\n );\n }\n this.#unsubscribe = this.#receiver.subscribe((packet) => this.#receive(packet));\n }\n\n async start(): Promise<void> {\n await this.#enqueue(async () => {\n if (this.#started) return;\n const record = await this.#persist(\"load viewer state\", () => this.#store.load());\n if (record) await this.#applyUniverses(record.selectedUniverses, false);\n this.#started = true;\n });\n }\n\n getSelectedUniverses(): readonly number[] {\n return this.#selected;\n }\n\n setSelectedUniverses(universes: readonly number[]): Promise<readonly number[]> {\n return this.#enqueue(async () => {\n await this.#applyUniverses(universes, true);\n return this.#selected;\n });\n }\n\n addUniverse(universe: number): Promise<readonly number[]> {\n return this.setSelectedUniverses([...this.#selected, universe]);\n }\n\n removeUniverse(universe: number): Promise<readonly number[]> {\n return this.setSelectedUniverses(this.#selected.filter((item) => item !== universe));\n }\n\n subscribe(listener: (packet: ViewerPacket) => void): () => void {\n this.#assertOpen();\n this.#assertListenerCapacity();\n this.#listeners.add(listener);\n return () => this.#listeners.delete(listener);\n }\n\n packets(capacity = this.#streamCapacity): ViewerPacketStream {\n this.#assertOpen();\n this.#assertListenerCapacity();\n if (!Number.isInteger(capacity) || capacity < 1) {\n throw new SacnValidationError(\"Stream capacity must be a positive integer.\", \"INVALID_FRAME\");\n }\n let stream: PacketStream;\n stream = new PacketStream(\n capacity,\n () => {\n this.#droppedUpdates += 1;\n },\n () => this.#streams.delete(stream),\n );\n this.#streams.add(stream);\n return stream;\n }\n\n getTelemetry(): ViewerTelemetry {\n return Object.freeze({\n selectedUniverses: this.#selected,\n packetsReceived: this.#packetsReceived,\n droppedUpdates: this.#droppedUpdates,\n streamCount: this.#streams.size,\n });\n }\n\n async close(): Promise<void> {\n if (this.#closed) return;\n this.#closed = true;\n await this.#queue;\n this.#unsubscribe();\n for (const stream of [...this.#streams]) stream.close();\n this.#listeners.clear();\n const errors: unknown[] = [];\n if (this.#ownsReceiver) {\n try {\n await this.#receiver.close();\n } catch (error) {\n errors.push(error);\n }\n }\n if (this.#ownsStore) {\n try {\n await this.#persist(\"close viewer store\", async () => {\n await this.#store.close?.();\n });\n } catch (error) {\n errors.push(error);\n }\n }\n if (errors.length === 1) throw errors[0];\n if (errors.length > 1) {\n throw new AggregateError(errors, \"Viewer shutdown failed.\");\n }\n }\n\n async #applyUniverses(universes: readonly number[], save: boolean): Promise<void> {\n const next = normalizeUniverses(universes, this.#maxUniverses);\n const previousSelection = this.#selected;\n const previous = new Set(previousSelection);\n const desired = new Set(next);\n try {\n for (const universe of previousSelection) {\n if (!desired.has(universe)) await this.#receiver.removeUniverse(universe);\n }\n for (const universe of next) {\n if (!previous.has(universe)) await this.#receiver.addUniverse(universe);\n }\n this.#selected = next;\n if (save) {\n await this.#persist(\"save viewer state\", () =>\n this.#store.save({\n selectedUniverses: next,\n updatedAt: this.#clock.now(),\n }),\n );\n }\n } catch (error) {\n try {\n for (const universe of next) {\n if (!previous.has(universe)) {\n await this.#receiver.removeUniverse(universe);\n }\n }\n for (const universe of previousSelection) {\n if (!desired.has(universe)) {\n await this.#receiver.addUniverse(universe);\n }\n }\n this.#selected = previousSelection;\n } catch (rollbackError) {\n throw new AggregateError(\n [error, rollbackError],\n \"Viewer universe update and rollback failed.\",\n );\n }\n throw error;\n }\n }\n\n #receive(packet: ReceiverPacket): void {\n if (this.#closed || !this.#selected.includes(packet.universe)) return;\n const normalized = normalizePacket(packet, this.#clock.now());\n this.#packetsReceived += 1;\n for (const listener of this.#listeners) {\n try {\n listener(normalized);\n } catch (error) {\n this.#logger.warn?.(\"Viewer packet listener failed.\", { error });\n }\n }\n for (const stream of this.#streams) stream.push(normalized);\n }\n\n #enqueue<T>(operation: () => Promise<T>): Promise<T> {\n if (this.#closed) {\n return Promise.reject(new SacnLifecycleError(\"Viewer service is closed.\"));\n }\n const result = this.#queue.then(operation);\n this.#queue = result.then(() => undefined, () => undefined);\n return result;\n }\n\n async #persist<T>(action: string, operation: () => Promise<T>): Promise<T> {\n try {\n return await operation();\n } catch (error) {\n if (error instanceof PersistenceError) throw error;\n throw new PersistenceError(`Failed to ${action}.`, error);\n }\n }\n\n #assertOpen(): void {\n if (this.#closed) throw new SacnLifecycleError(\"Viewer service is closed.\");\n }\n\n #assertListenerCapacity(): void {\n if (this.#listeners.size + this.#streams.size >= this.#maxListeners) {\n throw new SacnLifecycleError(\n `Viewer subscriber limit of ${this.#maxListeners} has been reached.`,\n );\n }\n }\n}\n\nconst cloneRecord = (record: ViewerRecord): ViewerRecord =>\n Object.freeze({\n selectedUniverses: Object.freeze([...record.selectedUniverses]),\n updatedAt: record.updatedAt,\n });\n\nexport class MemoryViewerStore implements ViewerStore {\n #record: ViewerRecord | null = null;\n\n async load(): Promise<ViewerRecord | null> {\n return this.#record ? cloneRecord(this.#record) : null;\n }\n\n async save(record: ViewerRecord): Promise<void> {\n this.#record = cloneRecord(record);\n }\n}\n"],"mappings":"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"}
|
package/dist/node.d.ts
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { A as SacnSourceOptions, C as Receiver, S as OutputTransport, T as ReceiverPacketListener, d as Logger, g as OutputAddress, v as OutputPacket } from "./contracts-C4kpAdZq.js";
|
|
2
|
+
import { t as SacnSource } from "./source-D_XNWXS9.js";
|
|
3
|
+
import { Buffer } from "node:buffer";
|
|
4
|
+
//#region src/node.d.ts
|
|
5
|
+
/** Test helper: close and clear the Node active-source registry. */
|
|
6
|
+
declare const flushActiveSacnSourcesForTests: () => Promise<void>;
|
|
7
|
+
/** Test helper: whether process signal handlers are installed. */
|
|
8
|
+
declare const areProcessHandlersInstalledForTests: () => boolean;
|
|
9
|
+
interface NodeRuntimeTelemetry {
|
|
10
|
+
readonly cpuUsage: {
|
|
11
|
+
readonly systemMicroseconds: number;
|
|
12
|
+
readonly userMicroseconds: number;
|
|
13
|
+
};
|
|
14
|
+
readonly memoryUsage: {
|
|
15
|
+
readonly arrayBuffersBytes: number;
|
|
16
|
+
readonly externalBytes: number;
|
|
17
|
+
readonly heapTotalBytes: number;
|
|
18
|
+
readonly heapUsedBytes: number;
|
|
19
|
+
readonly rssBytes: number;
|
|
20
|
+
};
|
|
21
|
+
readonly pid: number;
|
|
22
|
+
readonly uptimeSeconds: number;
|
|
23
|
+
}
|
|
24
|
+
declare const getNodeRuntimeTelemetry: () => NodeRuntimeTelemetry;
|
|
25
|
+
interface NodeSender {
|
|
26
|
+
send(packet: {
|
|
27
|
+
cid: Buffer;
|
|
28
|
+
payload: Record<number, number>;
|
|
29
|
+
priority: number;
|
|
30
|
+
sequence: number;
|
|
31
|
+
sourceName: string;
|
|
32
|
+
useRawDmxValues: true;
|
|
33
|
+
}): Promise<void>;
|
|
34
|
+
close(): unknown;
|
|
35
|
+
on?(event: "error", listener: (error: Error) => void): unknown;
|
|
36
|
+
}
|
|
37
|
+
interface NodeSenderOptions {
|
|
38
|
+
readonly universe: number;
|
|
39
|
+
readonly port: number;
|
|
40
|
+
readonly iface?: string;
|
|
41
|
+
readonly useUnicastDestination?: string;
|
|
42
|
+
}
|
|
43
|
+
interface NodeSacnTransportOptions {
|
|
44
|
+
readonly iface?: string;
|
|
45
|
+
readonly port?: number;
|
|
46
|
+
readonly sourceName?: string;
|
|
47
|
+
/** Optional unicast destination for testing or networks that require it. */
|
|
48
|
+
readonly unicastDestination?: string;
|
|
49
|
+
readonly senderFactory?: (options: NodeSenderOptions) => NodeSender;
|
|
50
|
+
readonly logger?: Logger;
|
|
51
|
+
}
|
|
52
|
+
interface CreateSacnSourceOptions extends Omit<SacnSourceOptions, "ownsTransport" | "transport"> {
|
|
53
|
+
readonly name?: string;
|
|
54
|
+
readonly transportOptions?: NodeSacnTransportOptions;
|
|
55
|
+
/**
|
|
56
|
+
* Install process SIGINT/SIGTERM/beforeExit handlers that close all
|
|
57
|
+
* registered Node sources. Defaults to true.
|
|
58
|
+
*/
|
|
59
|
+
readonly installProcessHandlers?: boolean;
|
|
60
|
+
}
|
|
61
|
+
declare const createSacnSource: (options?: CreateSacnSourceOptions) => SacnSource;
|
|
62
|
+
declare class NodeSacnTransport implements OutputTransport {
|
|
63
|
+
#private;
|
|
64
|
+
constructor(options?: NodeSacnTransportOptions);
|
|
65
|
+
send(packet: OutputPacket, signal: AbortSignal): Promise<void>;
|
|
66
|
+
closeOutput(address: Required<OutputAddress>): Promise<void>;
|
|
67
|
+
close(): Promise<void>;
|
|
68
|
+
}
|
|
69
|
+
interface SacnPacketLike {
|
|
70
|
+
readonly cid: Buffer;
|
|
71
|
+
readonly payload: Readonly<Record<number, number>>;
|
|
72
|
+
readonly payloadAsBuffer?: Buffer | null;
|
|
73
|
+
readonly priority: number;
|
|
74
|
+
readonly sequence: number;
|
|
75
|
+
readonly sourceAddress?: string;
|
|
76
|
+
readonly sourceName: string;
|
|
77
|
+
readonly universe: number;
|
|
78
|
+
}
|
|
79
|
+
interface NodeReceiverInstance {
|
|
80
|
+
addUniverse(universe: number): Promise<unknown> | unknown;
|
|
81
|
+
removeUniverse(universe: number): Promise<unknown> | unknown;
|
|
82
|
+
on(event: "packet", listener: (packet: SacnPacketLike) => void): unknown;
|
|
83
|
+
on(event: "error" | "PacketCorruption" | "PacketOutOfOrder", listener: (error: Error) => void): unknown;
|
|
84
|
+
off?(event: "packet", listener: (packet: SacnPacketLike) => void): unknown;
|
|
85
|
+
off?(event: "error" | "PacketCorruption" | "PacketOutOfOrder", listener: (error: Error) => void): unknown;
|
|
86
|
+
close(callback?: () => void): unknown;
|
|
87
|
+
readonly ready?: Promise<void>;
|
|
88
|
+
readonly socket?: {
|
|
89
|
+
address(): unknown;
|
|
90
|
+
once(event: "listening", listener: () => void): unknown;
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
interface NodeSacnReceiverOptions {
|
|
94
|
+
readonly universes?: readonly number[];
|
|
95
|
+
readonly iface?: string;
|
|
96
|
+
readonly port?: number;
|
|
97
|
+
readonly receiverFactory?: (options: {
|
|
98
|
+
universes: number[];
|
|
99
|
+
iface?: string;
|
|
100
|
+
port: number;
|
|
101
|
+
}) => NodeReceiverInstance;
|
|
102
|
+
readonly logger?: Logger;
|
|
103
|
+
}
|
|
104
|
+
declare class NodeSacnReceiver implements Receiver {
|
|
105
|
+
#private;
|
|
106
|
+
constructor(options?: NodeSacnReceiverOptions);
|
|
107
|
+
addUniverse(universe: number): Promise<void>;
|
|
108
|
+
removeUniverse(universe: number): Promise<void>;
|
|
109
|
+
subscribe(listener: ReceiverPacketListener): () => void;
|
|
110
|
+
close(): Promise<void>;
|
|
111
|
+
}
|
|
112
|
+
//#endregion
|
|
113
|
+
export { CreateSacnSourceOptions, NodeReceiverInstance, NodeRuntimeTelemetry, NodeSacnReceiver, NodeSacnReceiverOptions, NodeSacnTransport, NodeSacnTransportOptions, NodeSender, NodeSenderOptions, areProcessHandlersInstalledForTests, createSacnSource, flushActiveSacnSourcesForTests, getNodeRuntimeTelemetry };
|
|
114
|
+
//# sourceMappingURL=node.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node.d.ts","names":[],"sources":["../src/node.ts"],"mappings":";;;;;cA4Da,sCAA2C;;cAM3C;UAGI;WACP;aACC;aACA;;WAED;aACC;aACA;aACA;aACA;aACA;;WAED;WACA;;cAGG,+BAA8B;UAoB1B;EAChB,KAAK;IACJ,KAAK;IACL,SAAS;IACT;IACA;IACA;IACA;MACG;EACJ;EACA,IAAI,gBAAgB,WAAW,OAAO;;UAGtB;WACP;WACA;WACA;WACA;;UAGO;WACP;WACA;WACA;;WAEA;WACA,iBAAiB,SAAS,sBAAsB;WAChD,SAAS;;UAGF,gCACR,KAAK;WACJ;WACA,mBAAmB;;;;;WAKnB;;cAGG,mBAAgB,UACnB,4BACP;cAwJU,6BAA6B;;EAKzC,YAAY,UAAS;EAMf,KAAK,QAAQ,cAAc,QAAQ,cAAc;EAyFjD,YAAY,SAAS,SAAS,iBAAiB;EAQ/C,SAAS;;UAQN;WACA,KAAK;WACL,SAAS,SAAS;WAClB,kBAAkB;WAClB;WACA;WACA;WACA;WACA;;UAGO;EAChB,YAAY,mBAAmB;EAC/B,eAAe,mBAAmB;EAClC,GAAG,iBAAiB,WAAW,QAAQ;EACvC,GACC,0DACA,WAAW,OAAO;EAEnB,KAAK,iBAAiB,WAAW,QAAQ;EACzC,KACC,0DACA,WAAW,OAAO;EAEnB,MAAM;WACG,QAAQ;WACR;IACR;IACA,KAAK,oBAAoB;;;UAIV;WACP;WACA;WACA;WACA,mBAAmB;IAC3B;IACA;IACA;QACK;WACG,SAAS;;cAQN,4BAA4B;;EASxC,YAAY,UAAS;EAyEf,YAAY,mBAAmB;EAK/B,eAAe,mBAAmB;EAOxC,UAAU,UAAU;EAMd,SAAS"}
|