ne-room-digital-signage-contracts 0.1.1

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.
@@ -0,0 +1,298 @@
1
+ export * from "./types";
2
+ export declare const schemas: {
3
+ device: {
4
+ command: {
5
+ $schema: string;
6
+ title: string;
7
+ type: string;
8
+ additionalProperties: boolean;
9
+ required: string[];
10
+ properties: {
11
+ tenantId: {
12
+ type: string;
13
+ minLength: number;
14
+ };
15
+ deviceId: {
16
+ type: string;
17
+ minLength: number;
18
+ };
19
+ commandId: {
20
+ type: string;
21
+ minLength: number;
22
+ };
23
+ type: {
24
+ type: string;
25
+ enum: string[];
26
+ };
27
+ issuedAt: {
28
+ type: string;
29
+ format: string;
30
+ };
31
+ expiresAt: {
32
+ type: string;
33
+ format: string;
34
+ };
35
+ desiredVersion: {
36
+ type: string;
37
+ };
38
+ payload: {
39
+ type: string;
40
+ };
41
+ };
42
+ };
43
+ ack: {
44
+ $schema: string;
45
+ title: string;
46
+ type: string;
47
+ additionalProperties: boolean;
48
+ required: string[];
49
+ properties: {
50
+ tenantId: {
51
+ type: string;
52
+ minLength: number;
53
+ };
54
+ deviceId: {
55
+ type: string;
56
+ minLength: number;
57
+ };
58
+ commandId: {
59
+ type: string;
60
+ minLength: number;
61
+ };
62
+ status: {
63
+ type: string;
64
+ enum: string[];
65
+ };
66
+ timestamp: {
67
+ type: string;
68
+ format: string;
69
+ };
70
+ message: {
71
+ type: string;
72
+ };
73
+ details: {
74
+ type: string;
75
+ };
76
+ deviceAppVersion: {
77
+ type: string;
78
+ };
79
+ deviceOsVersion: {
80
+ type: string;
81
+ };
82
+ };
83
+ };
84
+ telemetry: {
85
+ $schema: string;
86
+ title: string;
87
+ type: string;
88
+ additionalProperties: boolean;
89
+ required: string[];
90
+ properties: {
91
+ tenantId: {
92
+ type: string;
93
+ minLength: number;
94
+ };
95
+ deviceId: {
96
+ type: string;
97
+ minLength: number;
98
+ };
99
+ timestamp: {
100
+ type: string;
101
+ format: string;
102
+ };
103
+ online: {
104
+ type: string;
105
+ };
106
+ health: {
107
+ type: string;
108
+ additionalProperties: boolean;
109
+ properties: {
110
+ cpuPct: {
111
+ type: string;
112
+ minimum: number;
113
+ maximum: number;
114
+ };
115
+ memPct: {
116
+ type: string;
117
+ minimum: number;
118
+ maximum: number;
119
+ };
120
+ diskFreeBytes: {
121
+ type: string;
122
+ minimum: number;
123
+ };
124
+ diskTotalBytes: {
125
+ type: string;
126
+ minimum: number;
127
+ };
128
+ tempC: {
129
+ type: string;
130
+ };
131
+ };
132
+ };
133
+ playback: {
134
+ type: string;
135
+ additionalProperties: boolean;
136
+ properties: {
137
+ state: {
138
+ type: string;
139
+ enum: string[];
140
+ };
141
+ currentAssetId: {
142
+ type: string;
143
+ };
144
+ currentPlaylistId: {
145
+ type: string;
146
+ };
147
+ currentScheduleId: {
148
+ type: string;
149
+ };
150
+ };
151
+ };
152
+ network: {
153
+ type: string;
154
+ additionalProperties: boolean;
155
+ properties: {
156
+ type: {
157
+ type: string;
158
+ enum: string[];
159
+ };
160
+ rssi: {
161
+ type: string;
162
+ };
163
+ };
164
+ };
165
+ app: {
166
+ type: string;
167
+ additionalProperties: boolean;
168
+ properties: {
169
+ version: {
170
+ type: string;
171
+ };
172
+ build: {
173
+ type: string;
174
+ };
175
+ };
176
+ };
177
+ errors: {
178
+ type: string;
179
+ items: {
180
+ type: string;
181
+ additionalProperties: boolean;
182
+ required: string[];
183
+ properties: {
184
+ code: {
185
+ type: string;
186
+ };
187
+ message: {
188
+ type: string;
189
+ };
190
+ severity: {
191
+ type: string;
192
+ enum: string[];
193
+ };
194
+ };
195
+ };
196
+ };
197
+ };
198
+ };
199
+ manifest: {
200
+ $schema: string;
201
+ title: string;
202
+ type: string;
203
+ additionalProperties: boolean;
204
+ required: string[];
205
+ properties: {
206
+ tenantId: {
207
+ type: string;
208
+ };
209
+ deviceId: {
210
+ type: string;
211
+ };
212
+ manifestVersion: {
213
+ type: string;
214
+ };
215
+ manifestUrl: {
216
+ type: string;
217
+ format: string;
218
+ };
219
+ generatedAt: {
220
+ type: string;
221
+ format: string;
222
+ };
223
+ };
224
+ };
225
+ proofOfPlay: {
226
+ $schema: string;
227
+ title: string;
228
+ type: string;
229
+ additionalProperties: boolean;
230
+ required: string[];
231
+ properties: {
232
+ tenantId: {
233
+ type: string;
234
+ };
235
+ deviceId: {
236
+ type: string;
237
+ };
238
+ eventId: {
239
+ type: string;
240
+ minLength: number;
241
+ };
242
+ assetId: {
243
+ type: string;
244
+ };
245
+ playlistId: {
246
+ type: string;
247
+ };
248
+ scheduleId: {
249
+ type: string;
250
+ };
251
+ startedAt: {
252
+ type: string;
253
+ format: string;
254
+ };
255
+ endedAt: {
256
+ type: string;
257
+ format: string;
258
+ };
259
+ durationMs: {
260
+ type: string;
261
+ minimum: number;
262
+ };
263
+ outcome: {
264
+ type: string;
265
+ enum: string[];
266
+ };
267
+ failureReason: {
268
+ type: string;
269
+ };
270
+ };
271
+ };
272
+ };
273
+ admin: {
274
+ wsEvents: {
275
+ $schema: string;
276
+ title: string;
277
+ type: string;
278
+ additionalProperties: boolean;
279
+ required: string[];
280
+ properties: {
281
+ tenantId: {
282
+ type: string;
283
+ };
284
+ type: {
285
+ type: string;
286
+ enum: string[];
287
+ };
288
+ timestamp: {
289
+ type: string;
290
+ format: string;
291
+ };
292
+ payload: {
293
+ type: string;
294
+ };
295
+ };
296
+ };
297
+ };
298
+ };
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ var __importDefault = (this && this.__importDefault) || function (mod) {
17
+ return (mod && mod.__esModule) ? mod : { "default": mod };
18
+ };
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.schemas = void 0;
21
+ __exportStar(require("./types"), exports);
22
+ const command_json_1 = __importDefault(require("../schemas/device/command.json"));
23
+ const ack_json_1 = __importDefault(require("../schemas/device/ack.json"));
24
+ const telemetry_json_1 = __importDefault(require("../schemas/device/telemetry.json"));
25
+ const manifest_json_1 = __importDefault(require("../schemas/device/manifest.json"));
26
+ const proof_of_play_json_1 = __importDefault(require("../schemas/device/proof_of_play.json"));
27
+ const ws_events_json_1 = __importDefault(require("../schemas/admin/ws_events.json"));
28
+ exports.schemas = {
29
+ device: {
30
+ command: command_json_1.default,
31
+ ack: ack_json_1.default,
32
+ telemetry: telemetry_json_1.default,
33
+ manifest: manifest_json_1.default,
34
+ proofOfPlay: proof_of_play_json_1.default
35
+ },
36
+ admin: {
37
+ wsEvents: ws_events_json_1.default
38
+ }
39
+ };
@@ -0,0 +1,83 @@
1
+ export type UUID = string;
2
+ export type CommandType = "RELOAD_MANIFEST" | "REBOOT_APP" | "REBOOT_DEVICE" | "CLEAR_CACHE" | "SET_VOLUME" | "SET_BRIGHTNESS" | "CAPTURE_SCREENSHOT" | "PING";
3
+ export interface DeviceCommand {
4
+ tenantId: string;
5
+ deviceId: string;
6
+ commandId: UUID;
7
+ type: CommandType;
8
+ issuedAt: string;
9
+ expiresAt?: string;
10
+ desiredVersion?: string;
11
+ payload?: Record<string, unknown>;
12
+ }
13
+ export type CommandAckStatus = "ACCEPTED" | "COMPLETED" | "FAILED" | "REJECTED" | "EXPIRED";
14
+ export interface DeviceCommandAck {
15
+ tenantId: string;
16
+ deviceId: string;
17
+ commandId: UUID;
18
+ status: CommandAckStatus;
19
+ timestamp: string;
20
+ message?: string;
21
+ details?: Record<string, unknown>;
22
+ deviceAppVersion?: string;
23
+ deviceOsVersion?: string;
24
+ }
25
+ export interface DeviceTelemetry {
26
+ tenantId: string;
27
+ deviceId: string;
28
+ timestamp: string;
29
+ online: boolean;
30
+ health: {
31
+ cpuPct?: number;
32
+ memPct?: number;
33
+ diskFreeBytes?: number;
34
+ diskTotalBytes?: number;
35
+ tempC?: number;
36
+ };
37
+ playback?: {
38
+ state: "PLAYING" | "IDLE" | "ERROR";
39
+ currentAssetId?: string;
40
+ currentPlaylistId?: string;
41
+ currentScheduleId?: string;
42
+ };
43
+ network?: {
44
+ type?: "WIFI" | "ETHERNET" | "CELLULAR" | "UNKNOWN";
45
+ rssi?: number;
46
+ };
47
+ app?: {
48
+ version?: string;
49
+ build?: string;
50
+ };
51
+ errors?: Array<{
52
+ code: string;
53
+ message: string;
54
+ severity: "INFO" | "WARN" | "ERROR";
55
+ }>;
56
+ }
57
+ export interface DeviceManifestPointer {
58
+ tenantId: string;
59
+ deviceId: string;
60
+ manifestVersion: string;
61
+ manifestUrl: string;
62
+ generatedAt: string;
63
+ }
64
+ export interface ProofOfPlayEvent {
65
+ tenantId: string;
66
+ deviceId: string;
67
+ eventId: UUID;
68
+ assetId: string;
69
+ playlistId?: string;
70
+ scheduleId?: string;
71
+ startedAt: string;
72
+ endedAt?: string;
73
+ durationMs?: number;
74
+ outcome: "PLAYED" | "SKIPPED" | "FAILED";
75
+ failureReason?: string;
76
+ }
77
+ export type AdminWsEventType = "DEVICE_ONLINE_CHANGED" | "DEVICE_TELEMETRY_UPDATED" | "ALERT_RAISED" | "ALERT_RESOLVED" | "PUBLISH_PROGRESS" | "PUBLISH_COMPLETED";
78
+ export interface AdminWsEvent<T = unknown> {
79
+ tenantId: string;
80
+ type: AdminWsEventType;
81
+ timestamp: string;
82
+ payload: T;
83
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,103 @@
1
+ openapi: 3.0.3
2
+ info:
3
+ title: Digital Signage Admin API
4
+ version: 0.1.0
5
+ description: Admin REST API for multi-tenant Digital Signage SaaS.
6
+ servers:
7
+ - url: https://api.example.com
8
+ security:
9
+ - bearerAuth: []
10
+ paths:
11
+ /health:
12
+ get:
13
+ summary: Health check
14
+ responses:
15
+ "200":
16
+ description: OK
17
+ content:
18
+ application/json:
19
+ schema:
20
+ type: object
21
+ properties:
22
+ status: { type: string, example: ok }
23
+
24
+ /devices:
25
+ get:
26
+ summary: List devices (tenant-scoped)
27
+ parameters:
28
+ - in: query
29
+ name: siteId
30
+ schema: { type: string }
31
+ - in: query
32
+ name: status
33
+ schema:
34
+ type: string
35
+ enum: [ONLINE, OFFLINE, UNKNOWN]
36
+ responses:
37
+ "200":
38
+ description: Device list
39
+ content:
40
+ application/json:
41
+ schema:
42
+ type: object
43
+ properties:
44
+ items:
45
+ type: array
46
+ items: { $ref: "#/components/schemas/Device" }
47
+
48
+ /publish:
49
+ post:
50
+ summary: Publish schedule/manifest updates to devices
51
+ description: >
52
+ Creates a publish job and signals devices via MQTT to pull the latest manifest over HTTPS.
53
+ requestBody:
54
+ required: true
55
+ content:
56
+ application/json:
57
+ schema: { $ref: "#/components/schemas/PublishRequest" }
58
+ responses:
59
+ "202":
60
+ description: Accepted
61
+ content:
62
+ application/json:
63
+ schema: { $ref: "#/components/schemas/PublishJob" }
64
+
65
+ components:
66
+ securitySchemes:
67
+ bearerAuth:
68
+ type: http
69
+ scheme: bearer
70
+ bearerFormat: JWT
71
+ schemas:
72
+ Device:
73
+ type: object
74
+ required: [id, tenantId, label, status, lastSeenAt]
75
+ properties:
76
+ id: { type: string }
77
+ tenantId: { type: string }
78
+ label: { type: string }
79
+ status:
80
+ type: string
81
+ enum: [ONLINE, OFFLINE, UNKNOWN]
82
+ appVersion: { type: string }
83
+ osVersion: { type: string }
84
+ lastSeenAt: { type: string, format: date-time }
85
+
86
+ PublishRequest:
87
+ type: object
88
+ required: [target]
89
+ properties:
90
+ target:
91
+ type: object
92
+ description: Target selector (site/group/device)
93
+ additionalProperties: true
94
+
95
+ PublishJob:
96
+ type: object
97
+ required: [id, status, createdAt]
98
+ properties:
99
+ id: { type: string }
100
+ status:
101
+ type: string
102
+ enum: [QUEUED, RUNNING, COMPLETED, FAILED]
103
+ createdAt: { type: string, format: date-time }
package/package.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "ne-room-digital-signage-contracts",
3
+ "version": "0.1.1",
4
+ "description": "Contracts (OpenAPI, AsyncAPI, JSON Schemas) for Digital Signage platform",
5
+ "license": "UNLICENSED",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "files": [
9
+ "dist",
10
+ "openapi",
11
+ "asyncapi",
12
+ "schemas",
13
+ "generated"
14
+ ],
15
+ "scripts": {
16
+ "build": "tsc -p tsconfig.json",
17
+ "clean": "rm -rf dist",
18
+ "lint": "echo \"TODO: add spectral/asyncapi lint\"",
19
+ "validate": "echo \"TODO: add schema validation\""
20
+ },
21
+ "devDependencies": {
22
+ "typescript": "^5.5.0"
23
+ }
24
+ }
@@ -0,0 +1,35 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "AdminWsEvent",
4
+ "type": "object",
5
+ "additionalProperties": false,
6
+ "required": [
7
+ "tenantId",
8
+ "type",
9
+ "timestamp",
10
+ "payload"
11
+ ],
12
+ "properties": {
13
+ "tenantId": {
14
+ "type": "string"
15
+ },
16
+ "type": {
17
+ "type": "string",
18
+ "enum": [
19
+ "DEVICE_ONLINE_CHANGED",
20
+ "DEVICE_TELEMETRY_UPDATED",
21
+ "ALERT_RAISED",
22
+ "ALERT_RESOLVED",
23
+ "PUBLISH_PROGRESS",
24
+ "PUBLISH_COMPLETED"
25
+ ]
26
+ },
27
+ "timestamp": {
28
+ "type": "string",
29
+ "format": "date-time"
30
+ },
31
+ "payload": {
32
+ "type": "object"
33
+ }
34
+ }
35
+ }
@@ -0,0 +1,53 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "DeviceCommandAck",
4
+ "type": "object",
5
+ "additionalProperties": false,
6
+ "required": [
7
+ "tenantId",
8
+ "deviceId",
9
+ "commandId",
10
+ "status",
11
+ "timestamp"
12
+ ],
13
+ "properties": {
14
+ "tenantId": {
15
+ "type": "string",
16
+ "minLength": 1
17
+ },
18
+ "deviceId": {
19
+ "type": "string",
20
+ "minLength": 1
21
+ },
22
+ "commandId": {
23
+ "type": "string",
24
+ "minLength": 16
25
+ },
26
+ "status": {
27
+ "type": "string",
28
+ "enum": [
29
+ "ACCEPTED",
30
+ "COMPLETED",
31
+ "FAILED",
32
+ "REJECTED",
33
+ "EXPIRED"
34
+ ]
35
+ },
36
+ "timestamp": {
37
+ "type": "string",
38
+ "format": "date-time"
39
+ },
40
+ "message": {
41
+ "type": "string"
42
+ },
43
+ "details": {
44
+ "type": "object"
45
+ },
46
+ "deviceAppVersion": {
47
+ "type": "string"
48
+ },
49
+ "deviceOsVersion": {
50
+ "type": "string"
51
+ }
52
+ }
53
+ }
@@ -0,0 +1,54 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "DeviceCommand",
4
+ "type": "object",
5
+ "additionalProperties": false,
6
+ "required": [
7
+ "tenantId",
8
+ "deviceId",
9
+ "commandId",
10
+ "type",
11
+ "issuedAt"
12
+ ],
13
+ "properties": {
14
+ "tenantId": {
15
+ "type": "string",
16
+ "minLength": 1
17
+ },
18
+ "deviceId": {
19
+ "type": "string",
20
+ "minLength": 1
21
+ },
22
+ "commandId": {
23
+ "type": "string",
24
+ "minLength": 16
25
+ },
26
+ "type": {
27
+ "type": "string",
28
+ "enum": [
29
+ "RELOAD_MANIFEST",
30
+ "REBOOT_APP",
31
+ "REBOOT_DEVICE",
32
+ "CLEAR_CACHE",
33
+ "SET_VOLUME",
34
+ "SET_BRIGHTNESS",
35
+ "CAPTURE_SCREENSHOT",
36
+ "PING"
37
+ ]
38
+ },
39
+ "issuedAt": {
40
+ "type": "string",
41
+ "format": "date-time"
42
+ },
43
+ "expiresAt": {
44
+ "type": "string",
45
+ "format": "date-time"
46
+ },
47
+ "desiredVersion": {
48
+ "type": "string"
49
+ },
50
+ "payload": {
51
+ "type": "object"
52
+ }
53
+ }
54
+ }