@digitalpaws/starr 0.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/README.rst +75 -0
- package/data/.nfs.811bbb0d.43c34.4 +0 -0
- package/data/.nfs.81ba4cd0.ffff87804.4 +0 -0
- package/data/.nfs.82d127f7.fffff5704.4 +0 -0
- package/data/.nfs.82d127fe.fffff5704.4 +0 -0
- package/data/.nfs.82d159a5.fffff5aa4.4 +0 -0
- package/data/.nfs.82d159aa.fffff5aa4.4 +0 -0
- package/data/.nfs.82d15a9c.fffff5bb4.4 +0 -0
- package/data/.nfs.82d15aa1.fffff5bb4.4 +0 -0
- package/data/.nfs.82d15c65.fffff5c24.4 +0 -0
- package/data/.nfs.82d1852c.fffff5e24.4 +0 -0
- package/data/.nfs.82d18536.fffff5e24.4 +0 -0
- package/data/.nfs.82d18dbe.fffff5e44.4 +0 -0
- package/data/.nfs.82d18dc6.fffff5e44.4 +0 -0
- package/data/.nfs.8309a3f5.fffff82f4.4 +0 -0
- package/data/.nfs.8309a3fe.fffff82f4.4 +0 -0
- package/data/.nfs.8314122e.fffffb044.4 +0 -0
- package/data/.nfs.83141236.fffffb044.4 +0 -0
- package/data/.nfs.833c4fe9.fffffbc34.4 +0 -0
- package/data/.nfs.833c4ff3.fffffbc34.4 +0 -0
- package/data/logs/starr.log +66244 -0
- package/data/starr.db +0 -0
- package/data/starr.db-shm +0 -0
- package/data/starr.db-wal +0 -0
- package/data/starr.jwt +1 -0
- package/data/starr.key +1 -0
- package/dist/auth/auth-service.d.ts +42 -0
- package/dist/auth/auth-service.d.ts.map +1 -0
- package/dist/auth/auth-service.js +226 -0
- package/dist/auth/auth-service.js.map +1 -0
- package/dist/auth/http-server.d.ts +16 -0
- package/dist/auth/http-server.d.ts.map +1 -0
- package/dist/auth/http-server.js +207 -0
- package/dist/auth/http-server.js.map +1 -0
- package/dist/auth/jwt-secret.d.ts +6 -0
- package/dist/auth/jwt-secret.d.ts.map +1 -0
- package/dist/auth/jwt-secret.js +51 -0
- package/dist/auth/jwt-secret.js.map +1 -0
- package/dist/auth/oidc/oidc-flow.d.ts +60 -0
- package/dist/auth/oidc/oidc-flow.d.ts.map +1 -0
- package/dist/auth/oidc/oidc-flow.js +201 -0
- package/dist/auth/oidc/oidc-flow.js.map +1 -0
- package/dist/auth/oidc/oidc-provider-service.d.ts +59 -0
- package/dist/auth/oidc/oidc-provider-service.d.ts.map +1 -0
- package/dist/auth/oidc/oidc-provider-service.js +124 -0
- package/dist/auth/oidc/oidc-provider-service.js.map +1 -0
- package/dist/auth/oidc/user-service.d.ts +67 -0
- package/dist/auth/oidc/user-service.d.ts.map +1 -0
- package/dist/auth/oidc/user-service.js +177 -0
- package/dist/auth/oidc/user-service.js.map +1 -0
- package/dist/auth/rate-limiter.d.ts +31 -0
- package/dist/auth/rate-limiter.d.ts.map +1 -0
- package/dist/auth/rate-limiter.js +70 -0
- package/dist/auth/rate-limiter.js.map +1 -0
- package/dist/config/config-service.d.ts +83 -0
- package/dist/config/config-service.d.ts.map +1 -0
- package/dist/config/config-service.js +309 -0
- package/dist/config/config-service.js.map +1 -0
- package/dist/config/validate.d.ts +12 -0
- package/dist/config/validate.d.ts.map +1 -0
- package/dist/config/validate.js +140 -0
- package/dist/config/validate.js.map +1 -0
- package/dist/content-types/registry.d.ts +75 -0
- package/dist/content-types/registry.d.ts.map +1 -0
- package/dist/content-types/registry.js +171 -0
- package/dist/content-types/registry.js.map +1 -0
- package/dist/datastore/db.d.ts +9 -0
- package/dist/datastore/db.d.ts.map +1 -0
- package/dist/datastore/db.js +27 -0
- package/dist/datastore/db.js.map +1 -0
- package/dist/datastore/encrypt.d.ts +9 -0
- package/dist/datastore/encrypt.d.ts.map +1 -0
- package/dist/datastore/encrypt.js +84 -0
- package/dist/datastore/encrypt.js.map +1 -0
- package/dist/datastore/migrations.d.ts +10 -0
- package/dist/datastore/migrations.d.ts.map +1 -0
- package/dist/datastore/migrations.js +340 -0
- package/dist/datastore/migrations.js.map +1 -0
- package/dist/datastore/storage.d.ts +4 -0
- package/dist/datastore/storage.d.ts.map +1 -0
- package/dist/datastore/storage.js +60 -0
- package/dist/datastore/storage.js.map +1 -0
- package/dist/events/event-bus.d.ts +15 -0
- package/dist/events/event-bus.d.ts.map +1 -0
- package/dist/events/event-bus.js +140 -0
- package/dist/events/event-bus.js.map +1 -0
- package/dist/events/spine.d.ts +31 -0
- package/dist/events/spine.d.ts.map +1 -0
- package/dist/events/spine.js +68 -0
- package/dist/events/spine.js.map +1 -0
- package/dist/events/trace.d.ts +24 -0
- package/dist/events/trace.d.ts.map +1 -0
- package/dist/events/trace.js +33 -0
- package/dist/events/trace.js.map +1 -0
- package/dist/host.d.ts +65 -0
- package/dist/host.d.ts.map +1 -0
- package/dist/host.js +94 -0
- package/dist/host.js.map +1 -0
- package/dist/library/importer.d.ts +29 -0
- package/dist/library/importer.d.ts.map +1 -0
- package/dist/library/importer.js +145 -0
- package/dist/library/importer.js.map +1 -0
- package/dist/library/library-cache.d.ts +46 -0
- package/dist/library/library-cache.d.ts.map +1 -0
- package/dist/library/library-cache.js +152 -0
- package/dist/library/library-cache.js.map +1 -0
- package/dist/library/library-config.d.ts +12 -0
- package/dist/library/library-config.d.ts.map +1 -0
- package/dist/library/library-config.js +10 -0
- package/dist/library/library-config.js.map +1 -0
- package/dist/library/library-scanner.d.ts +62 -0
- package/dist/library/library-scanner.d.ts.map +1 -0
- package/dist/library/library-scanner.js +336 -0
- package/dist/library/library-scanner.js.map +1 -0
- package/dist/library/library-service.d.ts +65 -0
- package/dist/library/library-service.d.ts.map +1 -0
- package/dist/library/library-service.js +197 -0
- package/dist/library/library-service.js.map +1 -0
- package/dist/library/metadata-matcher.d.ts +56 -0
- package/dist/library/metadata-matcher.d.ts.map +1 -0
- package/dist/library/metadata-matcher.js +207 -0
- package/dist/library/metadata-matcher.js.map +1 -0
- package/dist/library/naming.d.ts +8 -0
- package/dist/library/naming.d.ts.map +1 -0
- package/dist/library/naming.js +47 -0
- package/dist/library/naming.js.map +1 -0
- package/dist/library/scan-controller.d.ts +95 -0
- package/dist/library/scan-controller.d.ts.map +1 -0
- package/dist/library/scan-controller.js +379 -0
- package/dist/library/scan-controller.js.map +1 -0
- package/dist/library/source-resolver.d.ts +17 -0
- package/dist/library/source-resolver.d.ts.map +1 -0
- package/dist/library/source-resolver.js +75 -0
- package/dist/library/source-resolver.js.map +1 -0
- package/dist/logging/logger.d.ts +3 -0
- package/dist/logging/logger.d.ts.map +1 -0
- package/dist/logging/logger.js +107 -0
- package/dist/logging/logger.js.map +1 -0
- package/dist/main.d.ts +36 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +229 -0
- package/dist/main.js.map +1 -0
- package/dist/plugins/context.d.ts +10 -0
- package/dist/plugins/context.d.ts.map +1 -0
- package/dist/plugins/context.js +110 -0
- package/dist/plugins/context.js.map +1 -0
- package/dist/plugins/discovery.d.ts +2 -0
- package/dist/plugins/discovery.d.ts.map +1 -0
- package/dist/plugins/discovery.js +32 -0
- package/dist/plugins/discovery.js.map +1 -0
- package/dist/plugins/loader.d.ts +9 -0
- package/dist/plugins/loader.d.ts.map +1 -0
- package/dist/plugins/loader.js +245 -0
- package/dist/plugins/loader.js.map +1 -0
- package/dist/state/request-intake.d.ts +26 -0
- package/dist/state/request-intake.d.ts.map +1 -0
- package/dist/state/request-intake.js +74 -0
- package/dist/state/request-intake.js.map +1 -0
- package/dist/state/state-store.d.ts +146 -0
- package/dist/state/state-store.d.ts.map +1 -0
- package/dist/state/state-store.js +465 -0
- package/dist/state/state-store.js.map +1 -0
- package/dist/state/trace-store.d.ts +12 -0
- package/dist/state/trace-store.d.ts.map +1 -0
- package/dist/state/trace-store.js +24 -0
- package/dist/state/trace-store.js.map +1 -0
- package/dist/types/plugin.d.ts +93 -0
- package/dist/types/plugin.d.ts.map +1 -0
- package/dist/types/plugin.js +4 -0
- package/dist/types/plugin.js.map +1 -0
- package/dist/web/index.d.ts +10 -0
- package/dist/web/index.d.ts.map +1 -0
- package/dist/web/index.js +153 -0
- package/dist/web/index.js.map +1 -0
- package/dist/web/routes/activity.d.ts +6 -0
- package/dist/web/routes/activity.d.ts.map +1 -0
- package/dist/web/routes/activity.js +31 -0
- package/dist/web/routes/activity.js.map +1 -0
- package/dist/web/routes/auth.d.ts +6 -0
- package/dist/web/routes/auth.d.ts.map +1 -0
- package/dist/web/routes/auth.js +142 -0
- package/dist/web/routes/auth.js.map +1 -0
- package/dist/web/routes/config.d.ts +7 -0
- package/dist/web/routes/config.d.ts.map +1 -0
- package/dist/web/routes/config.js +204 -0
- package/dist/web/routes/config.js.map +1 -0
- package/dist/web/routes/content-types.d.ts +6 -0
- package/dist/web/routes/content-types.d.ts.map +1 -0
- package/dist/web/routes/content-types.js +29 -0
- package/dist/web/routes/content-types.js.map +1 -0
- package/dist/web/routes/discovery.d.ts +6 -0
- package/dist/web/routes/discovery.d.ts.map +1 -0
- package/dist/web/routes/discovery.js +111 -0
- package/dist/web/routes/discovery.js.map +1 -0
- package/dist/web/routes/library-import.d.ts +6 -0
- package/dist/web/routes/library-import.d.ts.map +1 -0
- package/dist/web/routes/library-import.js +120 -0
- package/dist/web/routes/library-import.js.map +1 -0
- package/dist/web/routes/library-management.d.ts +6 -0
- package/dist/web/routes/library-management.d.ts.map +1 -0
- package/dist/web/routes/library-management.js +120 -0
- package/dist/web/routes/library-management.js.map +1 -0
- package/dist/web/routes/library.d.ts +6 -0
- package/dist/web/routes/library.d.ts.map +1 -0
- package/dist/web/routes/library.js +28 -0
- package/dist/web/routes/library.js.map +1 -0
- package/dist/web/routes/oidc.d.ts +9 -0
- package/dist/web/routes/oidc.d.ts.map +1 -0
- package/dist/web/routes/oidc.js +203 -0
- package/dist/web/routes/oidc.js.map +1 -0
- package/dist/web/routes/requests.d.ts +6 -0
- package/dist/web/routes/requests.d.ts.map +1 -0
- package/dist/web/routes/requests.js +183 -0
- package/dist/web/routes/requests.js.map +1 -0
- package/dist/web/routes/sse.d.ts +6 -0
- package/dist/web/routes/sse.d.ts.map +1 -0
- package/dist/web/routes/sse.js +54 -0
- package/dist/web/routes/sse.js.map +1 -0
- package/package.json +33 -0
- package/package.json.license +2 -0
- package/src/auth/auth-service.ts +333 -0
- package/src/auth/http-server.ts +249 -0
- package/src/auth/jwt-secret.ts +65 -0
- package/src/auth/oidc/oidc-flow.ts +266 -0
- package/src/auth/oidc/oidc-provider-service.ts +174 -0
- package/src/auth/oidc/user-service.ts +227 -0
- package/src/auth/rate-limiter.ts +85 -0
- package/src/config/config-service.ts +434 -0
- package/src/config/validate.ts +153 -0
- package/src/content-types/registry.ts +194 -0
- package/src/datastore/db.ts +38 -0
- package/src/datastore/encrypt.ts +107 -0
- package/src/datastore/migrations.ts +367 -0
- package/src/datastore/storage.ts +83 -0
- package/src/events/event-bus.ts +180 -0
- package/src/events/spine.ts +87 -0
- package/src/events/trace.ts +38 -0
- package/src/host.ts +130 -0
- package/src/library/importer.ts +174 -0
- package/src/library/library-cache.ts +212 -0
- package/src/library/library-config.ts +22 -0
- package/src/library/library-scanner.ts +404 -0
- package/src/library/library-service.ts +282 -0
- package/src/library/metadata-matcher.ts +285 -0
- package/src/library/naming.ts +59 -0
- package/src/library/scan-controller.ts +490 -0
- package/src/library/source-resolver.ts +92 -0
- package/src/logging/logger.ts +115 -0
- package/src/main.ts +364 -0
- package/src/plugins/context.ts +138 -0
- package/src/plugins/discovery.ts +29 -0
- package/src/plugins/loader.ts +309 -0
- package/src/state/request-intake.ts +101 -0
- package/src/state/state-store.ts +621 -0
- package/src/state/trace-store.ts +27 -0
- package/src/types/plugin.ts +110 -0
- package/src/web/index.ts +182 -0
- package/src/web/routes/activity.ts +41 -0
- package/src/web/routes/auth.ts +170 -0
- package/src/web/routes/config.ts +282 -0
- package/src/web/routes/content-types.ts +42 -0
- package/src/web/routes/discovery.ts +156 -0
- package/src/web/routes/library-import.ts +196 -0
- package/src/web/routes/library-management.ts +140 -0
- package/src/web/routes/library.ts +46 -0
- package/src/web/routes/oidc.ts +260 -0
- package/src/web/routes/requests.ts +250 -0
- package/src/web/routes/sse.ts +92 -0
- package/tests/auth.test.ts +510 -0
- package/tests/config-route.test.ts +345 -0
- package/tests/config.test.ts +612 -0
- package/tests/content-types.test.ts +376 -0
- package/tests/datastore.test.ts +345 -0
- package/tests/e2e.test.ts +430 -0
- package/tests/event-bus.test.ts +925 -0
- package/tests/host.test.ts +449 -0
- package/tests/library-cache.test.ts +171 -0
- package/tests/library-scanner.test.ts +177 -0
- package/tests/library.test.ts +210 -0
- package/tests/loader-context.test.ts +644 -0
- package/tests/logger-jsonl.test.ts +154 -0
- package/tests/metadata-matcher.test.ts +198 -0
- package/tests/oidc.test.ts +218 -0
- package/tests/scan-controller.test.ts +328 -0
- package/tests/source-resolver.test.ts +100 -0
- package/tests/starr-video-integration.test.ts +153 -0
- package/tests/state-store.test.ts +700 -0
- package/tests/trace-history.test.ts +356 -0
- package/tsconfig.json +8 -0
- package/tsconfig.json.license +2 -0
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
// SPDX-License-Identifier: 0BSD
|
|
2
|
+
// SPDX-FileCopyrightText: 2025 Digi <digitalpaws@proton.me>
|
|
3
|
+
const CREATE_MIGRATIONS_TABLE = `
|
|
4
|
+
CREATE TABLE IF NOT EXISTS _migrations (
|
|
5
|
+
id INTEGER PRIMARY KEY,
|
|
6
|
+
name TEXT NOT NULL UNIQUE,
|
|
7
|
+
applied_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
8
|
+
);
|
|
9
|
+
`;
|
|
10
|
+
export function runMigrations(db, migrations, logger) {
|
|
11
|
+
db.exec(CREATE_MIGRATIONS_TABLE);
|
|
12
|
+
const applied = new Set(db
|
|
13
|
+
.prepare("SELECT id FROM _migrations")
|
|
14
|
+
.all()
|
|
15
|
+
.map((row) => row.id));
|
|
16
|
+
const pending = migrations
|
|
17
|
+
.filter((m) => !applied.has(m.id))
|
|
18
|
+
.sort((a, b) => a.id - b.id);
|
|
19
|
+
if (pending.length === 0) {
|
|
20
|
+
logger.debug("no pending migrations");
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
logger.info("running migrations", { count: pending.length });
|
|
24
|
+
const insert = db.prepare("INSERT INTO _migrations (id, name) VALUES (@id, @name)");
|
|
25
|
+
const runOne = db.transaction((migrations) => {
|
|
26
|
+
for (const m of migrations) {
|
|
27
|
+
logger.debug("applying migration", { id: m.id, name: m.name });
|
|
28
|
+
db.exec(m.up);
|
|
29
|
+
insert.run({ id: m.id, name: m.name });
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
runOne(pending);
|
|
33
|
+
logger.info("migrations complete");
|
|
34
|
+
}
|
|
35
|
+
// ── Core migrations ──────────────────────────────────────────
|
|
36
|
+
export const CORE_MIGRATIONS = [
|
|
37
|
+
{
|
|
38
|
+
id: 1,
|
|
39
|
+
name: "create_plugin_storage",
|
|
40
|
+
up: `
|
|
41
|
+
CREATE TABLE IF NOT EXISTS plugin_storage (
|
|
42
|
+
plugin_id TEXT NOT NULL,
|
|
43
|
+
key TEXT NOT NULL,
|
|
44
|
+
value TEXT NOT NULL,
|
|
45
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
46
|
+
PRIMARY KEY (plugin_id, key)
|
|
47
|
+
);
|
|
48
|
+
`,
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
id: 2,
|
|
52
|
+
name: "create_plugin_config",
|
|
53
|
+
up: `
|
|
54
|
+
CREATE TABLE IF NOT EXISTS plugin_config (
|
|
55
|
+
plugin_id TEXT NOT NULL PRIMARY KEY,
|
|
56
|
+
schema TEXT NOT NULL DEFAULT '{}',
|
|
57
|
+
"values" TEXT NOT NULL DEFAULT '{}',
|
|
58
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
59
|
+
);
|
|
60
|
+
`,
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
id: 3,
|
|
64
|
+
name: "create_tracked_requests",
|
|
65
|
+
up: `
|
|
66
|
+
CREATE TABLE IF NOT EXISTS tracked_requests (
|
|
67
|
+
request_id TEXT NOT NULL PRIMARY KEY,
|
|
68
|
+
content_type_id TEXT NOT NULL,
|
|
69
|
+
content_identity TEXT NOT NULL,
|
|
70
|
+
item TEXT NOT NULL,
|
|
71
|
+
owner_user_id TEXT NOT NULL,
|
|
72
|
+
watchers TEXT NOT NULL DEFAULT '[]',
|
|
73
|
+
status TEXT NOT NULL,
|
|
74
|
+
status_detail TEXT,
|
|
75
|
+
chosen_release_id TEXT,
|
|
76
|
+
attempts INTEGER NOT NULL DEFAULT 0,
|
|
77
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
78
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
79
|
+
);
|
|
80
|
+
CREATE INDEX IF NOT EXISTS idx_tracked_requests_identity
|
|
81
|
+
ON tracked_requests(content_identity);
|
|
82
|
+
`,
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
id: 4,
|
|
86
|
+
name: "create_trace_log",
|
|
87
|
+
up: `
|
|
88
|
+
CREATE TABLE IF NOT EXISTS trace_log (
|
|
89
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
90
|
+
trace_id TEXT NOT NULL,
|
|
91
|
+
request_id TEXT NOT NULL,
|
|
92
|
+
event_type TEXT NOT NULL,
|
|
93
|
+
event_data TEXT NOT NULL,
|
|
94
|
+
timestamp TEXT NOT NULL
|
|
95
|
+
);
|
|
96
|
+
CREATE INDEX IF NOT EXISTS idx_trace_log_request
|
|
97
|
+
ON trace_log(request_id);
|
|
98
|
+
CREATE INDEX IF NOT EXISTS idx_trace_log_trace
|
|
99
|
+
ON trace_log(trace_id, id);
|
|
100
|
+
`,
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
id: 5,
|
|
104
|
+
name: "create_accounts_and_sessions",
|
|
105
|
+
up: `
|
|
106
|
+
CREATE TABLE IF NOT EXISTS admin_accounts (
|
|
107
|
+
username TEXT NOT NULL PRIMARY KEY,
|
|
108
|
+
password_hash TEXT NOT NULL,
|
|
109
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
110
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
CREATE TABLE IF NOT EXISTS sessions (
|
|
114
|
+
session_id TEXT NOT NULL PRIMARY KEY,
|
|
115
|
+
user_id TEXT NOT NULL REFERENCES admin_accounts(username) ON DELETE CASCADE,
|
|
116
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
117
|
+
expires_at TEXT NOT NULL
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_user_id
|
|
121
|
+
ON sessions(user_id);
|
|
122
|
+
`,
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
id: 6,
|
|
126
|
+
name: "create_users_and_oidc_providers",
|
|
127
|
+
up: `
|
|
128
|
+
-- Users table: unified account for local admin and OIDC users
|
|
129
|
+
CREATE TABLE IF NOT EXISTS users (
|
|
130
|
+
id TEXT NOT NULL PRIMARY KEY, -- UUID
|
|
131
|
+
username TEXT NOT NULL UNIQUE,
|
|
132
|
+
display_name TEXT,
|
|
133
|
+
avatar_url TEXT,
|
|
134
|
+
role TEXT NOT NULL DEFAULT 'user' CHECK(role IN ('admin', 'user')),
|
|
135
|
+
provider TEXT NOT NULL DEFAULT 'local' CHECK(provider IN ('local', 'oidc')),
|
|
136
|
+
oidc_sub TEXT, -- OIDC 'sub' claim (unique per provider)
|
|
137
|
+
oidc_provider_id TEXT REFERENCES oidc_providers(id) ON DELETE SET NULL,
|
|
138
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
139
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
CREATE INDEX IF NOT EXISTS idx_users_oidc_sub
|
|
143
|
+
ON users(oidc_sub, oidc_provider_id);
|
|
144
|
+
|
|
145
|
+
-- OIDC provider configuration
|
|
146
|
+
CREATE TABLE IF NOT EXISTS oidc_providers (
|
|
147
|
+
id TEXT NOT NULL PRIMARY KEY, -- UUID
|
|
148
|
+
name TEXT NOT NULL,
|
|
149
|
+
issuer_url TEXT NOT NULL,
|
|
150
|
+
client_id TEXT NOT NULL,
|
|
151
|
+
client_secret TEXT NOT NULL, -- encrypted at rest
|
|
152
|
+
scopes TEXT NOT NULL DEFAULT 'openid profile email',
|
|
153
|
+
role_attribute TEXT, -- JSONPath to a claim, e.g. "$.starr_roles"
|
|
154
|
+
default_role TEXT NOT NULL DEFAULT 'user' CHECK(default_role IN ('admin', 'user')),
|
|
155
|
+
enabled INTEGER NOT NULL DEFAULT 1,
|
|
156
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
157
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
-- Temporary state for in-flight OIDC authorization flows
|
|
161
|
+
CREATE TABLE IF NOT EXISTS oidc_auth_states (
|
|
162
|
+
state TEXT NOT NULL PRIMARY KEY, -- random CSRF token
|
|
163
|
+
nonce TEXT NOT NULL,
|
|
164
|
+
code_verifier TEXT NOT NULL,
|
|
165
|
+
provider_id TEXT NOT NULL REFERENCES oidc_providers(id) ON DELETE CASCADE,
|
|
166
|
+
redirect_to TEXT NOT NULL DEFAULT '/browse',
|
|
167
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
CREATE INDEX IF NOT EXISTS idx_oidc_auth_states_created
|
|
171
|
+
ON oidc_auth_states(created_at);
|
|
172
|
+
|
|
173
|
+
-- Recreate sessions table without FK constraint so OIDC user UUIDs work
|
|
174
|
+
CREATE TABLE IF NOT EXISTS sessions_new (
|
|
175
|
+
session_id TEXT NOT NULL PRIMARY KEY,
|
|
176
|
+
user_id TEXT NOT NULL,
|
|
177
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
178
|
+
expires_at TEXT NOT NULL
|
|
179
|
+
);
|
|
180
|
+
INSERT INTO sessions_new (session_id, user_id, created_at, expires_at)
|
|
181
|
+
SELECT session_id, user_id, created_at, expires_at FROM sessions;
|
|
182
|
+
DROP TABLE sessions;
|
|
183
|
+
ALTER TABLE sessions_new RENAME TO sessions;
|
|
184
|
+
|
|
185
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_user_id
|
|
186
|
+
ON sessions(user_id);
|
|
187
|
+
|
|
188
|
+
-- Migrate existing admin to users table
|
|
189
|
+
INSERT OR IGNORE INTO users (id, username, display_name, role, provider, created_at, updated_at)
|
|
190
|
+
SELECT
|
|
191
|
+
'admin', -- id (fixed key for the local admin)
|
|
192
|
+
username, -- username from admin_accounts
|
|
193
|
+
username, -- display_name (same as username)
|
|
194
|
+
'admin', -- role
|
|
195
|
+
'local', -- provider
|
|
196
|
+
COALESCE(created_at, datetime('now')),
|
|
197
|
+
COALESCE(updated_at, datetime('now'))
|
|
198
|
+
FROM admin_accounts;
|
|
199
|
+
`,
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
id: 7,
|
|
203
|
+
name: "create_library_tracking",
|
|
204
|
+
up: `
|
|
205
|
+
-- Track the on-disk library path for each imported request
|
|
206
|
+
CREATE TABLE IF NOT EXISTS library_paths (
|
|
207
|
+
request_id TEXT NOT NULL PRIMARY KEY REFERENCES tracked_requests(request_id) ON DELETE CASCADE,
|
|
208
|
+
library_path TEXT NOT NULL,
|
|
209
|
+
library_root TEXT NOT NULL,
|
|
210
|
+
file_size INTEGER,
|
|
211
|
+
checksum TEXT,
|
|
212
|
+
imported_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
213
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
-- Add library_path column to tracked_requests for quick access
|
|
217
|
+
ALTER TABLE tracked_requests ADD COLUMN library_path TEXT;
|
|
218
|
+
`,
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
id: 8,
|
|
222
|
+
name: "create_library_cache",
|
|
223
|
+
up: `
|
|
224
|
+
-- Cache of imported item metadata for fast Browse loading.
|
|
225
|
+
-- Populated on import and refreshed on host start.
|
|
226
|
+
CREATE TABLE IF NOT EXISTS library_cache (
|
|
227
|
+
request_id TEXT NOT NULL PRIMARY KEY REFERENCES tracked_requests(request_id) ON DELETE CASCADE,
|
|
228
|
+
content_type_id TEXT NOT NULL,
|
|
229
|
+
content_identity TEXT NOT NULL,
|
|
230
|
+
title TEXT NOT NULL,
|
|
231
|
+
sort_title TEXT,
|
|
232
|
+
summary TEXT,
|
|
233
|
+
release_date TEXT,
|
|
234
|
+
images TEXT, -- JSON array of ContentImage
|
|
235
|
+
external_ids TEXT NOT NULL, -- JSON Record<string, string>
|
|
236
|
+
fields TEXT, -- JSON Record<string, unknown>
|
|
237
|
+
library_path TEXT NOT NULL,
|
|
238
|
+
file_size INTEGER,
|
|
239
|
+
imported_at TEXT NOT NULL,
|
|
240
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
CREATE INDEX IF NOT EXISTS idx_library_cache_content_type
|
|
244
|
+
ON library_cache(content_type_id);
|
|
245
|
+
|
|
246
|
+
CREATE INDEX IF NOT EXISTS idx_library_cache_identity
|
|
247
|
+
ON library_cache(content_identity);
|
|
248
|
+
`,
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
id: 9,
|
|
252
|
+
name: "create_libraries",
|
|
253
|
+
up: `
|
|
254
|
+
CREATE TABLE IF NOT EXISTS libraries (
|
|
255
|
+
id TEXT NOT NULL PRIMARY KEY,
|
|
256
|
+
name TEXT NOT NULL UNIQUE,
|
|
257
|
+
description TEXT,
|
|
258
|
+
is_default INTEGER NOT NULL DEFAULT 0,
|
|
259
|
+
default_library_root TEXT NOT NULL DEFAULT '/media/library',
|
|
260
|
+
roots TEXT NOT NULL DEFAULT '{}',
|
|
261
|
+
link_type TEXT NOT NULL DEFAULT 'hardlink' CHECK(link_type IN ('move','hardlink','symlink','copy')),
|
|
262
|
+
import_subtitles INTEGER NOT NULL DEFAULT 1,
|
|
263
|
+
subtitle_extensions TEXT NOT NULL DEFAULT '["srt","ass","ssa","sub","vtt"]',
|
|
264
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
265
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
266
|
+
);
|
|
267
|
+
|
|
268
|
+
CREATE TABLE IF NOT EXISTS library_content_type_defaults (
|
|
269
|
+
library_id TEXT NOT NULL REFERENCES libraries(id) ON DELETE CASCADE,
|
|
270
|
+
content_type_id TEXT NOT NULL,
|
|
271
|
+
PRIMARY KEY (content_type_id)
|
|
272
|
+
);
|
|
273
|
+
|
|
274
|
+
CREATE INDEX IF NOT EXISTS idx_library_content_type_defaults_library
|
|
275
|
+
ON library_content_type_defaults(library_id);
|
|
276
|
+
`,
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
id: 10,
|
|
280
|
+
name: "add_instance_id_to_plugin_tables",
|
|
281
|
+
up: `
|
|
282
|
+
CREATE TABLE IF NOT EXISTS plugin_config_new (
|
|
283
|
+
plugin_id TEXT NOT NULL,
|
|
284
|
+
instance_id TEXT NOT NULL DEFAULT 'default',
|
|
285
|
+
schema TEXT NOT NULL DEFAULT '{}',
|
|
286
|
+
"values" TEXT NOT NULL DEFAULT '{}',
|
|
287
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
288
|
+
PRIMARY KEY (plugin_id, instance_id)
|
|
289
|
+
);
|
|
290
|
+
|
|
291
|
+
INSERT INTO plugin_config_new (plugin_id, instance_id, schema, "values", updated_at)
|
|
292
|
+
SELECT plugin_id, 'default', schema, "values", updated_at FROM plugin_config;
|
|
293
|
+
|
|
294
|
+
DROP TABLE plugin_config;
|
|
295
|
+
ALTER TABLE plugin_config_new RENAME TO plugin_config;
|
|
296
|
+
|
|
297
|
+
CREATE TABLE IF NOT EXISTS plugin_storage_new (
|
|
298
|
+
plugin_id TEXT NOT NULL,
|
|
299
|
+
instance_id TEXT NOT NULL DEFAULT 'default',
|
|
300
|
+
key TEXT NOT NULL,
|
|
301
|
+
value TEXT NOT NULL,
|
|
302
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
303
|
+
PRIMARY KEY (plugin_id, instance_id, key)
|
|
304
|
+
);
|
|
305
|
+
|
|
306
|
+
INSERT INTO plugin_storage_new (plugin_id, instance_id, key, value, updated_at)
|
|
307
|
+
SELECT plugin_id, 'default', key, value, updated_at FROM plugin_storage;
|
|
308
|
+
|
|
309
|
+
DROP TABLE plugin_storage;
|
|
310
|
+
ALTER TABLE plugin_storage_new RENAME TO plugin_storage;
|
|
311
|
+
`,
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
id: 11,
|
|
315
|
+
name: "add_library_id_to_tracked_requests",
|
|
316
|
+
up: `
|
|
317
|
+
ALTER TABLE tracked_requests ADD COLUMN library_id TEXT REFERENCES libraries(id);
|
|
318
|
+
`,
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
id: 12,
|
|
322
|
+
name: "migrate_existing_imported_to_downloaded",
|
|
323
|
+
up: `
|
|
324
|
+
UPDATE tracked_requests
|
|
325
|
+
SET status = 'downloaded', updated_at = datetime('now')
|
|
326
|
+
WHERE status = 'imported';
|
|
327
|
+
`,
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
id: 13,
|
|
331
|
+
name: "remove_orphaned_core_configs",
|
|
332
|
+
up: `
|
|
333
|
+
-- Remove leftover _core.* config rows that were replaced by the
|
|
334
|
+
-- library service and multi-instance systems (Task 039).
|
|
335
|
+
DELETE FROM plugin_config WHERE plugin_id IN ('_core.library', '_core.downloads');
|
|
336
|
+
DELETE FROM plugin_storage WHERE plugin_id IN ('_core.library', '_core.downloads');
|
|
337
|
+
`,
|
|
338
|
+
},
|
|
339
|
+
];
|
|
340
|
+
//# sourceMappingURL=migrations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrations.js","sourceRoot":"","sources":["../../src/datastore/migrations.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/datastore/storage.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD,wBAAgB,mBAAmB,CACjC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,QAAQ,EAAE,MAAM,EAChB,UAAU,SAAY,GACrB,aAAa,CAwEf"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// SPDX-License-Identifier: 0BSD
|
|
2
|
+
// SPDX-FileCopyrightText: 2025 Digi <digitalpaws@proton.me>
|
|
3
|
+
export function createPluginStorage(db, pluginId, instanceId = "default") {
|
|
4
|
+
const getStmt = db.prepare("SELECT value FROM plugin_storage WHERE plugin_id = @pluginId AND instance_id = @instanceId AND key = @key");
|
|
5
|
+
const setStmt = db.prepare(`
|
|
6
|
+
INSERT INTO plugin_storage (plugin_id, instance_id, key, value, updated_at)
|
|
7
|
+
VALUES (@pluginId, @instanceId, @key, @value, datetime('now'))
|
|
8
|
+
ON CONFLICT(plugin_id, instance_id, key) DO UPDATE SET
|
|
9
|
+
value = @value,
|
|
10
|
+
updated_at = datetime('now')
|
|
11
|
+
`);
|
|
12
|
+
const deleteStmt = db.prepare("DELETE FROM plugin_storage WHERE plugin_id = @pluginId AND instance_id = @instanceId AND key = @key");
|
|
13
|
+
const listAllStmt = db.prepare(`SELECT key, value FROM plugin_storage
|
|
14
|
+
WHERE plugin_id = @pluginId AND instance_id = @instanceId
|
|
15
|
+
ORDER BY key`);
|
|
16
|
+
const listPrefixStmt = db.prepare(`SELECT key, value FROM plugin_storage
|
|
17
|
+
WHERE plugin_id = @pluginId AND instance_id = @instanceId AND key LIKE @prefix
|
|
18
|
+
ORDER BY key`);
|
|
19
|
+
const deleteAllStmt = db.prepare("DELETE FROM plugin_storage WHERE plugin_id = @pluginId AND instance_id = @instanceId");
|
|
20
|
+
return {
|
|
21
|
+
async get(key) {
|
|
22
|
+
const row = getStmt.get({ pluginId, instanceId, key });
|
|
23
|
+
if (!row)
|
|
24
|
+
return undefined;
|
|
25
|
+
try {
|
|
26
|
+
return JSON.parse(row.value);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
async set(key, value) {
|
|
33
|
+
setStmt.run({ pluginId, instanceId, key, value: JSON.stringify(value) });
|
|
34
|
+
},
|
|
35
|
+
async delete(key) {
|
|
36
|
+
deleteStmt.run({ pluginId, instanceId, key });
|
|
37
|
+
},
|
|
38
|
+
async list(prefix) {
|
|
39
|
+
const stmt = prefix !== undefined ? listPrefixStmt : listAllStmt;
|
|
40
|
+
const params = prefix !== undefined
|
|
41
|
+
? { pluginId, instanceId, prefix: `${prefix}%` }
|
|
42
|
+
: { pluginId, instanceId };
|
|
43
|
+
const rows = stmt.all(params);
|
|
44
|
+
return rows.map((row) => {
|
|
45
|
+
let value;
|
|
46
|
+
try {
|
|
47
|
+
value = JSON.parse(row.value);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
value = undefined;
|
|
51
|
+
}
|
|
52
|
+
return { key: row.key, value: value };
|
|
53
|
+
});
|
|
54
|
+
},
|
|
55
|
+
async deleteAll() {
|
|
56
|
+
deleteAllStmt.run({ pluginId, instanceId });
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/datastore/storage.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,4DAA4D;AAK5D,MAAM,UAAU,mBAAmB,CACjC,EAAqB,EACrB,QAAgB,EAChB,UAAU,GAAG,SAAS;IAEtB,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,CACxB,2GAA2G,CAC5G,CAAC;IACF,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC;;;;;;GAM1B,CAAC,CAAC;IACH,MAAM,UAAU,GAAG,EAAE,CAAC,OAAO,CAC3B,qGAAqG,CACtG,CAAC;IACF,MAAM,WAAW,GAAG,EAAE,CAAC,OAAO,CAC5B;;kBAEc,CACf,CAAC;IACF,MAAM,cAAc,GAAG,EAAE,CAAC,OAAO,CAC/B;;kBAEc,CACf,CAAC;IACF,MAAM,aAAa,GAAG,EAAE,CAAC,OAAO,CAC9B,sFAAsF,CACvF,CAAC;IAEF,OAAO;QACL,KAAK,CAAC,GAAG,CAAI,GAAW;YACtB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,EAAE,CAExC,CAAC;YACd,IAAI,CAAC,GAAG;gBAAE,OAAO,SAAS,CAAC;YAC3B,IAAI,CAAC;gBACH,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAM,CAAC;YACpC,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,SAAS,CAAC;YACnB,CAAC;QACH,CAAC;QAED,KAAK,CAAC,GAAG,CAAI,GAAW,EAAE,KAAQ;YAChC,OAAO,CAAC,GAAG,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC3E,CAAC;QAED,KAAK,CAAC,MAAM,CAAC,GAAW;YACtB,UAAU,CAAC,GAAG,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC;QAChD,CAAC;QAED,KAAK,CAAC,IAAI,CACR,MAAe;YAEf,MAAM,IAAI,GAAG,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,WAAW,CAAC;YACjE,MAAM,MAAM,GAAG,MAAM,KAAK,SAAS;gBACjC,CAAC,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,EAAE;gBAChD,CAAC,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC;YAC7B,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAA0C,CAAC;YACvE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;gBACtB,IAAI,KAAoB,CAAC;gBACzB,IAAI,CAAC;oBACH,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAM,CAAC;gBACrC,CAAC;gBAAC,MAAM,CAAC;oBACP,KAAK,GAAG,SAAS,CAAC;gBACpB,CAAC;gBACD,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,KAAU,EAAE,CAAC;YAC7C,CAAC,CAAC,CAAC;QACL,CAAC;QAED,KAAK,CAAC,SAAS;YACb,aAAa,CAAC,GAAG,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;QAC9C,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Logger } from "../types/plugin.js";
|
|
2
|
+
import type { EventBus } from "../types/plugin.js";
|
|
3
|
+
export declare class EventBusImpl {
|
|
4
|
+
private subscriptions;
|
|
5
|
+
private logger;
|
|
6
|
+
constructor(logger: Logger);
|
|
7
|
+
/** Returns an EventBus bound to the given plugin id. */
|
|
8
|
+
pluginBus(pluginId: string): EventBus;
|
|
9
|
+
/** Returns an EventBus with source="core". */
|
|
10
|
+
coreBus(): EventBus;
|
|
11
|
+
private _on;
|
|
12
|
+
private _emit;
|
|
13
|
+
private _request;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=event-bus.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-bus.d.ts","sourceRoot":"","sources":["../../src/events/event-bus.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EAEV,QAAQ,EAKT,MAAM,oBAAoB,CAAC;AAI5B,qBAAa,YAAY;IACvB,OAAO,CAAC,aAAa,CAAwC;IAC7D,OAAO,CAAC,MAAM,CAAS;gBAEX,MAAM,EAAE,MAAM;IAM1B,wDAAwD;IACxD,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ;IAUrC,8CAA8C;IAC9C,OAAO,IAAI,QAAQ;IAMnB,OAAO,CAAC,GAAG;IAcX,OAAO,CAAC,KAAK;IAuEb,OAAO,CAAC,QAAQ;CAkDjB"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
// SPDX-License-Identifier: 0BSD
|
|
2
|
+
// SPDX-FileCopyrightText: 2025 Digi <digitalpaws@proton.me>
|
|
3
|
+
import { randomUUID } from "node:crypto";
|
|
4
|
+
import { runInTraceContext, getCurrentTraceId } from "./trace.js";
|
|
5
|
+
import { getSpineSchemaVersion, validateSpineEmission } from "./spine.js";
|
|
6
|
+
export class EventBusImpl {
|
|
7
|
+
subscriptions = new Map();
|
|
8
|
+
logger;
|
|
9
|
+
constructor(logger) {
|
|
10
|
+
this.logger = logger.child("event-bus");
|
|
11
|
+
}
|
|
12
|
+
// ---- Public factory methods ---- //
|
|
13
|
+
/** Returns an EventBus bound to the given plugin id. */
|
|
14
|
+
pluginBus(pluginId) {
|
|
15
|
+
return {
|
|
16
|
+
on: (type, handler) => this._on(type, handler),
|
|
17
|
+
emit: (type, payload, opts) => this._emit(pluginId, type, payload, opts),
|
|
18
|
+
request: (type, payload, opts) => this._request(pluginId, type, payload, opts),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/** Returns an EventBus with source="core". */
|
|
22
|
+
coreBus() {
|
|
23
|
+
return this.pluginBus("core");
|
|
24
|
+
}
|
|
25
|
+
// ---- Private implementation ---- //
|
|
26
|
+
_on(type, handler) {
|
|
27
|
+
if (!this.subscriptions.has(type)) {
|
|
28
|
+
this.subscriptions.set(type, new Set());
|
|
29
|
+
}
|
|
30
|
+
const handlers = this.subscriptions.get(type);
|
|
31
|
+
handlers.add(handler);
|
|
32
|
+
return () => {
|
|
33
|
+
handlers.delete(handler);
|
|
34
|
+
if (handlers.size === 0) {
|
|
35
|
+
this.subscriptions.delete(type);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
_emit(source, type, payload, opts) {
|
|
40
|
+
const event = {
|
|
41
|
+
id: randomUUID(),
|
|
42
|
+
traceId: getCurrentTraceId(),
|
|
43
|
+
correlationId: opts?.correlationId,
|
|
44
|
+
source,
|
|
45
|
+
type,
|
|
46
|
+
timestamp: new Date().toISOString(),
|
|
47
|
+
schemaVersion: getSpineSchemaVersion(type),
|
|
48
|
+
payload,
|
|
49
|
+
reply: (replyType, replyPayload) => {
|
|
50
|
+
this._emit(source, replyType, replyPayload, {
|
|
51
|
+
correlationId: event.correlationId,
|
|
52
|
+
});
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
// Immutability (EN2)
|
|
56
|
+
Object.freeze(event);
|
|
57
|
+
this.logger.debug("emitting event", {
|
|
58
|
+
eventType: type,
|
|
59
|
+
source,
|
|
60
|
+
correlationId: event.correlationId,
|
|
61
|
+
});
|
|
62
|
+
// Spine validation — log at warn level if suspect (EBQ4, §9 CE2–CE3)
|
|
63
|
+
const violation = validateSpineEmission(source, type);
|
|
64
|
+
if (violation) {
|
|
65
|
+
this.logger.warn("spine emission warning", {
|
|
66
|
+
source,
|
|
67
|
+
eventType: type,
|
|
68
|
+
detail: violation,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
// Look up handlers
|
|
72
|
+
const handlers = this.subscriptions.get(type);
|
|
73
|
+
if (!handlers || handlers.size === 0) {
|
|
74
|
+
return; // silently dropped (DL5)
|
|
75
|
+
}
|
|
76
|
+
// Dispatch to each handler — error isolation per handler (DL2)
|
|
77
|
+
const logger = this.logger;
|
|
78
|
+
for (const handler of handlers) {
|
|
79
|
+
try {
|
|
80
|
+
const result = runInTraceContext(event, () => handler(event));
|
|
81
|
+
if (result instanceof Promise) {
|
|
82
|
+
result.catch((err) => {
|
|
83
|
+
logger.error("event handler rejected", {
|
|
84
|
+
eventType: type,
|
|
85
|
+
handlerSource: source,
|
|
86
|
+
error: String(err),
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
catch (err) {
|
|
92
|
+
logger.error("event handler threw", {
|
|
93
|
+
eventType: type,
|
|
94
|
+
handlerSource: source,
|
|
95
|
+
error: String(err),
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
_request(source, type, payload, opts) {
|
|
101
|
+
// Validate opts — programming errors, fail fast
|
|
102
|
+
if (!opts.responseType || opts.responseType.trim() === "") {
|
|
103
|
+
throw new Error("request(): responseType is required and must be non-empty");
|
|
104
|
+
}
|
|
105
|
+
if (!Number.isFinite(opts.windowMs) || opts.windowMs <= 0) {
|
|
106
|
+
throw new Error(`request(): windowMs must be a positive number, got ${opts.windowMs}`);
|
|
107
|
+
}
|
|
108
|
+
if (opts.max !== undefined && (!Number.isInteger(opts.max) || opts.max < 1)) {
|
|
109
|
+
throw new Error(`request(): max must be a positive integer, got ${opts.max}`);
|
|
110
|
+
}
|
|
111
|
+
const correlationId = randomUUID();
|
|
112
|
+
const replies = [];
|
|
113
|
+
return new Promise((resolve) => {
|
|
114
|
+
let settled = false;
|
|
115
|
+
const timer = setTimeout(() => {
|
|
116
|
+
if (settled)
|
|
117
|
+
return;
|
|
118
|
+
settled = true;
|
|
119
|
+
unsub();
|
|
120
|
+
resolve(replies);
|
|
121
|
+
}, opts.windowMs);
|
|
122
|
+
const unsub = this._on(opts.responseType, (evt) => {
|
|
123
|
+
if (settled)
|
|
124
|
+
return;
|
|
125
|
+
if (evt.correlationId === correlationId) {
|
|
126
|
+
replies.push(evt);
|
|
127
|
+
if (opts.max !== undefined && replies.length >= opts.max) {
|
|
128
|
+
settled = true;
|
|
129
|
+
clearTimeout(timer);
|
|
130
|
+
unsub();
|
|
131
|
+
resolve(replies);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
// Emit AFTER subscribing so synchronous replies are not missed
|
|
136
|
+
this._emit(source, type, payload, { correlationId });
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=event-bus.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-bus.js","sourceRoot":"","sources":["../../src/events/event-bus.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reserved spine namespace prefixes.
|
|
3
|
+
* The dotted unprefixed namespace is reserved for the core spine.
|
|
4
|
+
*/
|
|
5
|
+
export declare const SPINE_NAMESPACES: readonly ["content.", "release.", "download.", "import.", "library.", "discovery.", "item."];
|
|
6
|
+
export interface SpineEventMeta {
|
|
7
|
+
kind: "request" | "reply" | "notification";
|
|
8
|
+
/** Who is allowed to emit this event. */
|
|
9
|
+
producers: "core" | "metadata-plugin" | "indexer-plugin" | "selection-plugin" | "downloader-plugin";
|
|
10
|
+
schemaVersion: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* The v1 spine event catalog (spec §8).
|
|
14
|
+
*/
|
|
15
|
+
export declare const SPINE_EVENTS: Record<string, SpineEventMeta>;
|
|
16
|
+
/**
|
|
17
|
+
* Check whether an event type falls within the reserved spine namespace.
|
|
18
|
+
*/
|
|
19
|
+
export declare function isSpineType(type: string): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Return the schemaVersion for a spine type, or 1 as default for custom events.
|
|
22
|
+
*/
|
|
23
|
+
export declare function getSpineSchemaVersion(type: string): number;
|
|
24
|
+
/**
|
|
25
|
+
* Validate whether a source is allowed to emit the given spine event type.
|
|
26
|
+
*
|
|
27
|
+
* Returns an error message string if the emission is suspect, or null if it is fine.
|
|
28
|
+
* Per EBQ4 resolution, this only logs warnings; it does not reject.
|
|
29
|
+
*/
|
|
30
|
+
export declare function validateSpineEmission(source: string, type: string): string | null;
|
|
31
|
+
//# sourceMappingURL=spine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spine.d.ts","sourceRoot":"","sources":["../../src/events/spine.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,eAAO,MAAM,gBAAgB,8FAQnB,CAAC;AAEX,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,SAAS,GAAG,OAAO,GAAG,cAAc,CAAC;IAC3C,yCAAyC;IACzC,SAAS,EACL,MAAM,GACN,iBAAiB,GACjB,gBAAgB,GAChB,kBAAkB,GAClB,mBAAmB,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAiBvD,CAAC;AAEF;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAejF"}
|