openplugdj 1.0.0 → 1.0.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.
- package/dist/adapters/MemoryStore.d.ts +10 -0
- package/dist/adapters/MemoryStore.js +27 -0
- package/dist/adapters/RedisStore.d.ts +13 -0
- package/dist/adapters/RedisStore.js +48 -0
- package/dist/adapters/Store.d.ts +8 -0
- package/dist/adapters/Store.js +2 -0
- package/dist/core/DJ.d.ts +11 -0
- package/dist/core/DJ.js +30 -0
- package/dist/core/Player.d.ts +16 -0
- package/dist/core/Player.js +45 -0
- package/dist/core/Queue.d.ts +11 -0
- package/dist/core/Queue.js +31 -0
- package/dist/core/Room.d.ts +17 -0
- package/dist/core/Room.js +38 -0
- package/dist/events/EventTypes.d.ts +15 -0
- package/dist/events/EventTypes.js +2 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +33 -0
- package/dist/models/DJEntry.d.ts +8 -0
- package/dist/models/DJEntry.js +2 -0
- package/dist/models/Track.d.ts +8 -0
- package/dist/models/Track.js +2 -0
- package/dist/models/User.d.ts +7 -0
- package/dist/models/User.js +2 -0
- package/dist/services/MetadataService.d.ts +4 -0
- package/dist/services/MetadataService.js +2 -0
- package/dist/services/StreamService.d.ts +5 -0
- package/dist/services/StreamService.js +2 -0
- package/dist/services/VoteService.d.ts +10 -0
- package/dist/services/VoteService.js +26 -0
- package/dist/utils/time.d.ts +4 -0
- package/dist/utils/time.js +20 -0
- package/package.json +8 -3
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Store } from "./Store";
|
|
2
|
+
export declare class MemoryStore<T> implements Store<T> {
|
|
3
|
+
private map;
|
|
4
|
+
get(id: string): Promise<T | undefined>;
|
|
5
|
+
set(id: string, value: T): Promise<void>;
|
|
6
|
+
delete(id: string): Promise<void>;
|
|
7
|
+
getAll(): Promise<T[]>;
|
|
8
|
+
has(id: string): Promise<boolean>;
|
|
9
|
+
clear(): Promise<void>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MemoryStore = void 0;
|
|
4
|
+
class MemoryStore {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.map = new Map();
|
|
7
|
+
}
|
|
8
|
+
async get(id) {
|
|
9
|
+
return this.map.get(id);
|
|
10
|
+
}
|
|
11
|
+
async set(id, value) {
|
|
12
|
+
this.map.set(id, value);
|
|
13
|
+
}
|
|
14
|
+
async delete(id) {
|
|
15
|
+
this.map.delete(id);
|
|
16
|
+
}
|
|
17
|
+
async getAll() {
|
|
18
|
+
return Array.from(this.map.values());
|
|
19
|
+
}
|
|
20
|
+
async has(id) {
|
|
21
|
+
return this.map.has(id);
|
|
22
|
+
}
|
|
23
|
+
async clear() {
|
|
24
|
+
this.map.clear();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
exports.MemoryStore = MemoryStore;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Store } from "./Store";
|
|
2
|
+
export declare class RedisStore<T> implements Store<T> {
|
|
3
|
+
private redis;
|
|
4
|
+
private namespace;
|
|
5
|
+
constructor(redisUrl: string, namespace: string);
|
|
6
|
+
private key;
|
|
7
|
+
get(id: string): Promise<T | undefined>;
|
|
8
|
+
set(id: string, value: T): Promise<void>;
|
|
9
|
+
delete(id: string): Promise<void>;
|
|
10
|
+
getAll(): Promise<T[]>;
|
|
11
|
+
has(id: string): Promise<boolean>;
|
|
12
|
+
clear(): Promise<void>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.RedisStore = void 0;
|
|
7
|
+
const ioredis_1 = __importDefault(require("ioredis"));
|
|
8
|
+
class RedisStore {
|
|
9
|
+
constructor(redisUrl, namespace) {
|
|
10
|
+
this.redis = new ioredis_1.default(redisUrl);
|
|
11
|
+
this.namespace = namespace;
|
|
12
|
+
}
|
|
13
|
+
key(id) {
|
|
14
|
+
return `${this.namespace}:${id}`;
|
|
15
|
+
}
|
|
16
|
+
async get(id) {
|
|
17
|
+
const data = await this.redis.get(this.key(id));
|
|
18
|
+
if (!data)
|
|
19
|
+
return undefined;
|
|
20
|
+
return JSON.parse(data);
|
|
21
|
+
}
|
|
22
|
+
async set(id, value) {
|
|
23
|
+
await this.redis.set(this.key(id), JSON.stringify(value));
|
|
24
|
+
}
|
|
25
|
+
async delete(id) {
|
|
26
|
+
await this.redis.del(this.key(id));
|
|
27
|
+
}
|
|
28
|
+
async getAll() {
|
|
29
|
+
const keys = await this.redis.keys(`${this.namespace}:*`);
|
|
30
|
+
if (!keys.length)
|
|
31
|
+
return [];
|
|
32
|
+
const values = await this.redis.mget(...keys);
|
|
33
|
+
return values
|
|
34
|
+
.filter(Boolean)
|
|
35
|
+
.map(v => JSON.parse(v));
|
|
36
|
+
}
|
|
37
|
+
async has(id) {
|
|
38
|
+
const exists = await this.redis.exists(this.key(id));
|
|
39
|
+
return exists === 1;
|
|
40
|
+
}
|
|
41
|
+
async clear() {
|
|
42
|
+
const keys = await this.redis.keys(`${this.namespace}:*`);
|
|
43
|
+
if (keys.length) {
|
|
44
|
+
await this.redis.del(...keys);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.RedisStore = RedisStore;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { EventEmitter } from "events";
|
|
2
|
+
import { Room } from "./Room";
|
|
3
|
+
import { StreamService } from "../services/StreamService";
|
|
4
|
+
export declare class DJ extends EventEmitter {
|
|
5
|
+
private streamService;
|
|
6
|
+
private rooms;
|
|
7
|
+
constructor(streamService: StreamService);
|
|
8
|
+
createRoom(id: string): Room;
|
|
9
|
+
getRoom(id: string): Promise<Room | undefined>;
|
|
10
|
+
deleteRoom(id: string): void;
|
|
11
|
+
}
|
package/dist/core/DJ.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DJ = void 0;
|
|
4
|
+
const events_1 = require("events");
|
|
5
|
+
const Room_1 = require("./Room");
|
|
6
|
+
const MemoryStore_1 = require("../adapters/MemoryStore");
|
|
7
|
+
class DJ extends events_1.EventEmitter {
|
|
8
|
+
constructor(streamService) {
|
|
9
|
+
super();
|
|
10
|
+
this.streamService = streamService;
|
|
11
|
+
this.rooms = new MemoryStore_1.MemoryStore();
|
|
12
|
+
}
|
|
13
|
+
createRoom(id) {
|
|
14
|
+
const room = new Room_1.Room(id, this.streamService);
|
|
15
|
+
this.rooms.set(id, room);
|
|
16
|
+
this.emit("roomCreated", room);
|
|
17
|
+
return room;
|
|
18
|
+
}
|
|
19
|
+
getRoom(id) {
|
|
20
|
+
return this.rooms.get(id);
|
|
21
|
+
}
|
|
22
|
+
deleteRoom(id) {
|
|
23
|
+
const room = this.rooms.get(id);
|
|
24
|
+
if (!room)
|
|
25
|
+
return;
|
|
26
|
+
this.rooms.delete(id);
|
|
27
|
+
this.emit("roomDeleted", room);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
exports.DJ = DJ;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { EventEmitter } from "events";
|
|
2
|
+
import { Queue } from "./Queue";
|
|
3
|
+
import { StreamService } from "../services/StreamService";
|
|
4
|
+
import { DJEntry } from "../models/DJEntry";
|
|
5
|
+
export declare class Player extends EventEmitter {
|
|
6
|
+
private queue;
|
|
7
|
+
private streamService;
|
|
8
|
+
private current;
|
|
9
|
+
private voteService;
|
|
10
|
+
private playing;
|
|
11
|
+
constructor(queue: Queue, streamService: StreamService);
|
|
12
|
+
playNext(): Promise<void>;
|
|
13
|
+
vote(userId: string, type: "up" | "down"): void;
|
|
14
|
+
skip(): void;
|
|
15
|
+
getCurrent(): DJEntry | null;
|
|
16
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Player = void 0;
|
|
4
|
+
const events_1 = require("events");
|
|
5
|
+
const VoteService_1 = require("../services/VoteService");
|
|
6
|
+
class Player extends events_1.EventEmitter {
|
|
7
|
+
constructor(queue, streamService) {
|
|
8
|
+
super();
|
|
9
|
+
this.queue = queue;
|
|
10
|
+
this.streamService = streamService;
|
|
11
|
+
this.current = null;
|
|
12
|
+
this.voteService = new VoteService_1.VoteService();
|
|
13
|
+
this.playing = false;
|
|
14
|
+
}
|
|
15
|
+
async playNext() {
|
|
16
|
+
if (this.playing)
|
|
17
|
+
return;
|
|
18
|
+
const entry = this.queue.next();
|
|
19
|
+
if (!entry) {
|
|
20
|
+
this.emit("queueEmpty");
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
this.current = entry;
|
|
24
|
+
this.voteService.clear();
|
|
25
|
+
this.playing = true;
|
|
26
|
+
this.emit("trackStart", entry.track);
|
|
27
|
+
await this.streamService.play(entry.track);
|
|
28
|
+
this.emit("trackEnd", entry.track);
|
|
29
|
+
this.playing = false;
|
|
30
|
+
this.playNext();
|
|
31
|
+
}
|
|
32
|
+
vote(userId, type) {
|
|
33
|
+
this.voteService.vote(userId, type);
|
|
34
|
+
this.emit("voteUpdated", this.voteService.getResults());
|
|
35
|
+
}
|
|
36
|
+
skip() {
|
|
37
|
+
this.streamService.stop();
|
|
38
|
+
this.playing = false;
|
|
39
|
+
this.playNext();
|
|
40
|
+
}
|
|
41
|
+
getCurrent() {
|
|
42
|
+
return this.current;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
exports.Player = Player;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { DJEntry } from "../models/DJEntry";
|
|
2
|
+
export declare class Queue {
|
|
3
|
+
private entries;
|
|
4
|
+
add(entry: DJEntry): void;
|
|
5
|
+
next(): DJEntry | undefined;
|
|
6
|
+
remove(entryId: string): void;
|
|
7
|
+
reorder(from: number, to: number): void;
|
|
8
|
+
getAll(): DJEntry[];
|
|
9
|
+
size(): number;
|
|
10
|
+
clear(): void;
|
|
11
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Queue = void 0;
|
|
4
|
+
class Queue {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.entries = [];
|
|
7
|
+
}
|
|
8
|
+
add(entry) {
|
|
9
|
+
this.entries.push(entry);
|
|
10
|
+
}
|
|
11
|
+
next() {
|
|
12
|
+
return this.entries.shift();
|
|
13
|
+
}
|
|
14
|
+
remove(entryId) {
|
|
15
|
+
this.entries = this.entries.filter(e => e.id !== entryId);
|
|
16
|
+
}
|
|
17
|
+
reorder(from, to) {
|
|
18
|
+
const [item] = this.entries.splice(from, 1);
|
|
19
|
+
this.entries.splice(to, 0, item);
|
|
20
|
+
}
|
|
21
|
+
getAll() {
|
|
22
|
+
return [...this.entries];
|
|
23
|
+
}
|
|
24
|
+
size() {
|
|
25
|
+
return this.entries.length;
|
|
26
|
+
}
|
|
27
|
+
clear() {
|
|
28
|
+
this.entries = [];
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
exports.Queue = Queue;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { EventEmitter } from "events";
|
|
2
|
+
import { Queue } from "./Queue";
|
|
3
|
+
import { Player } from "./Player";
|
|
4
|
+
import { User } from "../models/User";
|
|
5
|
+
import { DJEntry } from "../models/DJEntry";
|
|
6
|
+
import { StreamService } from "../services/StreamService";
|
|
7
|
+
export declare class Room extends EventEmitter {
|
|
8
|
+
id: string;
|
|
9
|
+
private users;
|
|
10
|
+
queue: Queue;
|
|
11
|
+
player: Player;
|
|
12
|
+
constructor(id: string, streamService: StreamService);
|
|
13
|
+
addUser(user: User): void;
|
|
14
|
+
removeUser(userId: string): void;
|
|
15
|
+
addEntry(entry: DJEntry): void;
|
|
16
|
+
start(): void;
|
|
17
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Room = void 0;
|
|
4
|
+
const events_1 = require("events");
|
|
5
|
+
const Queue_1 = require("./Queue");
|
|
6
|
+
const Player_1 = require("./Player");
|
|
7
|
+
class Room extends events_1.EventEmitter {
|
|
8
|
+
constructor(id, streamService) {
|
|
9
|
+
super();
|
|
10
|
+
this.id = id;
|
|
11
|
+
this.users = new Map();
|
|
12
|
+
this.queue = new Queue_1.Queue();
|
|
13
|
+
this.player = new Player_1.Player(this.queue, streamService);
|
|
14
|
+
this.player.on("trackStart", t => this.emit("trackStart", t));
|
|
15
|
+
this.player.on("trackEnd", t => this.emit("trackEnd", t));
|
|
16
|
+
this.player.on("voteUpdated", v => this.emit("voteUpdated", v));
|
|
17
|
+
this.player.on("queueEmpty", () => this.emit("queueEmpty"));
|
|
18
|
+
}
|
|
19
|
+
addUser(user) {
|
|
20
|
+
this.users.set(user.id, user);
|
|
21
|
+
this.emit("userJoined", user);
|
|
22
|
+
}
|
|
23
|
+
removeUser(userId) {
|
|
24
|
+
const user = this.users.get(userId);
|
|
25
|
+
if (!user)
|
|
26
|
+
return;
|
|
27
|
+
this.users.delete(userId);
|
|
28
|
+
this.emit("userLeft", user);
|
|
29
|
+
}
|
|
30
|
+
addEntry(entry) {
|
|
31
|
+
this.queue.add(entry);
|
|
32
|
+
this.emit("queueUpdated", this.queue.getAll());
|
|
33
|
+
}
|
|
34
|
+
start() {
|
|
35
|
+
this.player.playNext();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
exports.Room = Room;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Track } from "../models/Track";
|
|
2
|
+
import { DJEntry } from "../models/DJEntry";
|
|
3
|
+
import { User } from "../models/User";
|
|
4
|
+
export interface RoomEvents {
|
|
5
|
+
userJoined: (user: User) => void;
|
|
6
|
+
userLeft: (user: User) => void;
|
|
7
|
+
trackStart: (track: Track) => void;
|
|
8
|
+
trackEnd: (track: Track) => void;
|
|
9
|
+
queueUpdated: (entries: DJEntry[]) => void;
|
|
10
|
+
voteUpdated: (votes: {
|
|
11
|
+
up: number;
|
|
12
|
+
down: number;
|
|
13
|
+
}) => void;
|
|
14
|
+
queueEmpty: () => void;
|
|
15
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { DJ } from "./core/DJ";
|
|
2
|
+
export { Room } from "./core/Room";
|
|
3
|
+
export { Player } from "./core/Player";
|
|
4
|
+
export { Queue } from "./core/Queue";
|
|
5
|
+
export * from "./models/Track";
|
|
6
|
+
export * from "./models/User";
|
|
7
|
+
export * from "./models/DJEntry";
|
|
8
|
+
export * from "./services/StreamService";
|
|
9
|
+
export * from "./services/MetadataService";
|
|
10
|
+
export * from "./adapters/MemoryStore";
|
|
11
|
+
export * from "./adapters/RedisStore";
|
|
12
|
+
export * from "./utils/time";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.Queue = exports.Player = exports.Room = exports.DJ = void 0;
|
|
18
|
+
var DJ_1 = require("./core/DJ");
|
|
19
|
+
Object.defineProperty(exports, "DJ", { enumerable: true, get: function () { return DJ_1.DJ; } });
|
|
20
|
+
var Room_1 = require("./core/Room");
|
|
21
|
+
Object.defineProperty(exports, "Room", { enumerable: true, get: function () { return Room_1.Room; } });
|
|
22
|
+
var Player_1 = require("./core/Player");
|
|
23
|
+
Object.defineProperty(exports, "Player", { enumerable: true, get: function () { return Player_1.Player; } });
|
|
24
|
+
var Queue_1 = require("./core/Queue");
|
|
25
|
+
Object.defineProperty(exports, "Queue", { enumerable: true, get: function () { return Queue_1.Queue; } });
|
|
26
|
+
__exportStar(require("./models/Track"), exports);
|
|
27
|
+
__exportStar(require("./models/User"), exports);
|
|
28
|
+
__exportStar(require("./models/DJEntry"), exports);
|
|
29
|
+
__exportStar(require("./services/StreamService"), exports);
|
|
30
|
+
__exportStar(require("./services/MetadataService"), exports);
|
|
31
|
+
__exportStar(require("./adapters/MemoryStore"), exports);
|
|
32
|
+
__exportStar(require("./adapters/RedisStore"), exports);
|
|
33
|
+
__exportStar(require("./utils/time"), exports);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.VoteService = void 0;
|
|
4
|
+
class VoteService {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.votes = new Map();
|
|
7
|
+
}
|
|
8
|
+
vote(userId, type) {
|
|
9
|
+
this.votes.set(userId, type);
|
|
10
|
+
}
|
|
11
|
+
clear() {
|
|
12
|
+
this.votes.clear();
|
|
13
|
+
}
|
|
14
|
+
getResults() {
|
|
15
|
+
let up = 0;
|
|
16
|
+
let down = 0;
|
|
17
|
+
for (const v of this.votes.values()) {
|
|
18
|
+
if (v === "up")
|
|
19
|
+
up++;
|
|
20
|
+
if (v === "down")
|
|
21
|
+
down++;
|
|
22
|
+
}
|
|
23
|
+
return { up, down, total: up - down };
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
exports.VoteService = VoteService;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.now = now;
|
|
4
|
+
exports.seconds = seconds;
|
|
5
|
+
exports.minutes = minutes;
|
|
6
|
+
exports.calculateRemaining = calculateRemaining;
|
|
7
|
+
function now() {
|
|
8
|
+
return Date.now();
|
|
9
|
+
}
|
|
10
|
+
function seconds(seconds) {
|
|
11
|
+
return seconds * 1000;
|
|
12
|
+
}
|
|
13
|
+
function minutes(minutes) {
|
|
14
|
+
return minutes * 60 * 1000;
|
|
15
|
+
}
|
|
16
|
+
function calculateRemaining(startTime, duration) {
|
|
17
|
+
const elapsed = now() - startTime;
|
|
18
|
+
const remaining = duration - elapsed;
|
|
19
|
+
return remaining > 0 ? remaining : 0;
|
|
20
|
+
}
|
package/package.json
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openplugdj",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "A lightweight DJ queue and room engine inspired by plug.dj",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": ["dist", "README.md", "LICENSE", "package.json"],
|
|
7
11
|
"scripts": {
|
|
8
12
|
"build": "tsc",
|
|
9
|
-
"dev": "tsc -w"
|
|
13
|
+
"dev": "tsc -w",
|
|
14
|
+
"prepublishOnly": "npm run build"
|
|
10
15
|
},
|
|
11
16
|
"keywords": ["dj", "queue", "music", "room", "realtime"],
|
|
12
17
|
"author": "bulondra",
|
|
@@ -19,4 +24,4 @@
|
|
|
19
24
|
"typescript": "^5.5.3"
|
|
20
25
|
},
|
|
21
26
|
"private": false
|
|
22
|
-
}
|
|
27
|
+
}
|