@ashdev/codex-plugin-sdk 1.0.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.
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Plugin server - handles JSON-RPC communication over stdio
3
+ */
4
+ import type { MetadataContentType, MetadataProvider } from "./types/capabilities.js";
5
+ import type { PluginManifest } from "./types/manifest.js";
6
+ /**
7
+ * Initialize parameters received from Codex
8
+ */
9
+ export interface InitializeParams {
10
+ /** Plugin configuration */
11
+ config?: Record<string, unknown>;
12
+ /** Plugin credentials (API keys, tokens, etc.) */
13
+ credentials?: Record<string, string>;
14
+ }
15
+ /**
16
+ * Options for creating a metadata plugin
17
+ */
18
+ export interface MetadataPluginOptions {
19
+ /** Plugin manifest - must have capabilities.metadataProvider with content types */
20
+ manifest: PluginManifest & {
21
+ capabilities: {
22
+ metadataProvider: MetadataContentType[];
23
+ };
24
+ };
25
+ /** MetadataProvider implementation */
26
+ provider: MetadataProvider;
27
+ /** Called when plugin receives initialize with credentials/config */
28
+ onInitialize?: (params: InitializeParams) => void | Promise<void>;
29
+ /** Log level (default: "info") */
30
+ logLevel?: "debug" | "info" | "warn" | "error";
31
+ }
32
+ /**
33
+ * Create and run a metadata provider plugin
34
+ *
35
+ * Creates a plugin server that handles JSON-RPC communication over stdio.
36
+ * The TypeScript compiler will ensure you implement all required methods.
37
+ *
38
+ * @example
39
+ * ```typescript
40
+ * import { createMetadataPlugin, type MetadataProvider } from "@ashdev/codex-plugin-sdk";
41
+ *
42
+ * const provider: MetadataProvider = {
43
+ * async search(params) {
44
+ * return {
45
+ * results: [{
46
+ * externalId: "123",
47
+ * title: "Example",
48
+ * alternateTitles: [],
49
+ * relevanceScore: 0.95,
50
+ * }],
51
+ * };
52
+ * },
53
+ * async get(params) {
54
+ * return {
55
+ * externalId: params.externalId,
56
+ * externalUrl: "https://example.com/123",
57
+ * alternateTitles: [],
58
+ * genres: [],
59
+ * tags: [],
60
+ * authors: [],
61
+ * artists: [],
62
+ * externalLinks: [],
63
+ * };
64
+ * },
65
+ * };
66
+ *
67
+ * createMetadataPlugin({
68
+ * manifest: {
69
+ * name: "my-plugin",
70
+ * displayName: "My Plugin",
71
+ * version: "1.0.0",
72
+ * description: "Example plugin",
73
+ * author: "Me",
74
+ * protocolVersion: "1.0",
75
+ * capabilities: { metadataProvider: ["series"] },
76
+ * },
77
+ * provider,
78
+ * });
79
+ * ```
80
+ */
81
+ export declare function createMetadataPlugin(options: MetadataPluginOptions): void;
82
+ /**
83
+ * @deprecated Use createMetadataPlugin instead
84
+ */
85
+ export declare function createSeriesMetadataPlugin(options: SeriesMetadataPluginOptions): void;
86
+ /**
87
+ * @deprecated Use MetadataPluginOptions instead
88
+ */
89
+ export interface SeriesMetadataPluginOptions {
90
+ /** Plugin manifest - must have capabilities.seriesMetadataProvider: true */
91
+ manifest: PluginManifest & {
92
+ capabilities: {
93
+ seriesMetadataProvider: true;
94
+ };
95
+ };
96
+ /** SeriesMetadataProvider implementation */
97
+ provider: MetadataProvider;
98
+ /** Called when plugin receives initialize with credentials/config */
99
+ onInitialize?: (params: InitializeParams) => void | Promise<void>;
100
+ /** Log level (default: "info") */
101
+ logLevel?: "debug" | "info" | "warn" | "error";
102
+ }
103
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AACrF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAsF1D;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,2BAA2B;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,kDAAkD;IAClD,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACtC;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,mFAAmF;IACnF,QAAQ,EAAE,cAAc,GAAG;QACzB,YAAY,EAAE;YAAE,gBAAgB,EAAE,mBAAmB,EAAE,CAAA;SAAE,CAAC;KAC3D,CAAC;IACF,sCAAsC;IACtC,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,qEAAqE;IACrE,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClE,kCAAkC;IAClC,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;CAChD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI,CA6BzE;AAMD;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,2BAA2B,GAAG,IAAI,CAarF;AAED;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C,4EAA4E;IAC5E,QAAQ,EAAE,cAAc,GAAG;QACzB,YAAY,EAAE;YAAE,sBAAsB,EAAE,IAAI,CAAA;SAAE,CAAC;KAChD,CAAC;IACF,4CAA4C;IAC5C,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,qEAAqE;IACrE,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClE,kCAAkC;IAClC,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;CAChD"}
package/dist/server.js ADDED
@@ -0,0 +1,306 @@
1
+ /**
2
+ * Plugin server - handles JSON-RPC communication over stdio
3
+ */
4
+ import { createInterface } from "node:readline";
5
+ import { PluginError } from "./errors.js";
6
+ import { createLogger } from "./logger.js";
7
+ import { JSON_RPC_ERROR_CODES, } from "./types/rpc.js";
8
+ /**
9
+ * Validate that the required string fields are present and non-empty
10
+ */
11
+ function validateStringFields(params, fields) {
12
+ if (params === null || params === undefined) {
13
+ return { field: "params", message: "params is required" };
14
+ }
15
+ if (typeof params !== "object") {
16
+ return { field: "params", message: "params must be an object" };
17
+ }
18
+ const obj = params;
19
+ for (const field of fields) {
20
+ const value = obj[field];
21
+ if (value === undefined || value === null) {
22
+ return { field, message: `${field} is required` };
23
+ }
24
+ if (typeof value !== "string") {
25
+ return { field, message: `${field} must be a string` };
26
+ }
27
+ if (value.trim() === "") {
28
+ return { field, message: `${field} cannot be empty` };
29
+ }
30
+ }
31
+ return null;
32
+ }
33
+ /**
34
+ * Validate MetadataSearchParams
35
+ */
36
+ function validateSearchParams(params) {
37
+ return validateStringFields(params, ["query"]);
38
+ }
39
+ /**
40
+ * Validate MetadataGetParams
41
+ */
42
+ function validateGetParams(params) {
43
+ return validateStringFields(params, ["externalId"]);
44
+ }
45
+ /**
46
+ * Validate MetadataMatchParams
47
+ */
48
+ function validateMatchParams(params) {
49
+ return validateStringFields(params, ["title"]);
50
+ }
51
+ /**
52
+ * Create an INVALID_PARAMS error response
53
+ */
54
+ function invalidParamsError(id, error) {
55
+ return {
56
+ jsonrpc: "2.0",
57
+ id,
58
+ error: {
59
+ code: JSON_RPC_ERROR_CODES.INVALID_PARAMS,
60
+ message: `Invalid params: ${error.message}`,
61
+ data: { field: error.field },
62
+ },
63
+ };
64
+ }
65
+ /**
66
+ * Create and run a metadata provider plugin
67
+ *
68
+ * Creates a plugin server that handles JSON-RPC communication over stdio.
69
+ * The TypeScript compiler will ensure you implement all required methods.
70
+ *
71
+ * @example
72
+ * ```typescript
73
+ * import { createMetadataPlugin, type MetadataProvider } from "@ashdev/codex-plugin-sdk";
74
+ *
75
+ * const provider: MetadataProvider = {
76
+ * async search(params) {
77
+ * return {
78
+ * results: [{
79
+ * externalId: "123",
80
+ * title: "Example",
81
+ * alternateTitles: [],
82
+ * relevanceScore: 0.95,
83
+ * }],
84
+ * };
85
+ * },
86
+ * async get(params) {
87
+ * return {
88
+ * externalId: params.externalId,
89
+ * externalUrl: "https://example.com/123",
90
+ * alternateTitles: [],
91
+ * genres: [],
92
+ * tags: [],
93
+ * authors: [],
94
+ * artists: [],
95
+ * externalLinks: [],
96
+ * };
97
+ * },
98
+ * };
99
+ *
100
+ * createMetadataPlugin({
101
+ * manifest: {
102
+ * name: "my-plugin",
103
+ * displayName: "My Plugin",
104
+ * version: "1.0.0",
105
+ * description: "Example plugin",
106
+ * author: "Me",
107
+ * protocolVersion: "1.0",
108
+ * capabilities: { metadataProvider: ["series"] },
109
+ * },
110
+ * provider,
111
+ * });
112
+ * ```
113
+ */
114
+ export function createMetadataPlugin(options) {
115
+ const { manifest, provider, onInitialize, logLevel = "info" } = options;
116
+ const logger = createLogger({ name: manifest.name, level: logLevel });
117
+ logger.info(`Starting plugin: ${manifest.displayName} v${manifest.version}`);
118
+ const rl = createInterface({
119
+ input: process.stdin,
120
+ terminal: false,
121
+ });
122
+ rl.on("line", (line) => {
123
+ void handleLine(line, manifest, provider, onInitialize, logger);
124
+ });
125
+ rl.on("close", () => {
126
+ logger.info("stdin closed, shutting down");
127
+ process.exit(0);
128
+ });
129
+ // Handle uncaught errors
130
+ process.on("uncaughtException", (error) => {
131
+ logger.error("Uncaught exception", error);
132
+ process.exit(1);
133
+ });
134
+ process.on("unhandledRejection", (reason) => {
135
+ logger.error("Unhandled rejection", reason);
136
+ });
137
+ }
138
+ // =============================================================================
139
+ // Backwards Compatibility (deprecated)
140
+ // =============================================================================
141
+ /**
142
+ * @deprecated Use createMetadataPlugin instead
143
+ */
144
+ export function createSeriesMetadataPlugin(options) {
145
+ // Convert legacy options to new format
146
+ const newOptions = {
147
+ ...options,
148
+ manifest: {
149
+ ...options.manifest,
150
+ capabilities: {
151
+ ...options.manifest.capabilities,
152
+ metadataProvider: ["series"],
153
+ },
154
+ },
155
+ };
156
+ createMetadataPlugin(newOptions);
157
+ }
158
+ // =============================================================================
159
+ // Internal Implementation
160
+ // =============================================================================
161
+ async function handleLine(line, manifest, provider, onInitialize, logger) {
162
+ const trimmed = line.trim();
163
+ if (!trimmed)
164
+ return;
165
+ let id = null;
166
+ try {
167
+ const request = JSON.parse(trimmed);
168
+ id = request.id;
169
+ logger.debug(`Received request: ${request.method}`, { id: request.id });
170
+ const response = await handleRequest(request, manifest, provider, onInitialize, logger);
171
+ // Shutdown handler writes response directly and returns null
172
+ if (response !== null) {
173
+ writeResponse(response);
174
+ }
175
+ }
176
+ catch (error) {
177
+ if (error instanceof SyntaxError) {
178
+ // JSON parse error
179
+ writeResponse({
180
+ jsonrpc: "2.0",
181
+ id: null,
182
+ error: {
183
+ code: JSON_RPC_ERROR_CODES.PARSE_ERROR,
184
+ message: "Parse error: invalid JSON",
185
+ },
186
+ });
187
+ }
188
+ else if (error instanceof PluginError) {
189
+ writeResponse({
190
+ jsonrpc: "2.0",
191
+ id,
192
+ error: error.toJsonRpcError(),
193
+ });
194
+ }
195
+ else {
196
+ const message = error instanceof Error ? error.message : "Unknown error";
197
+ logger.error("Request failed", error);
198
+ writeResponse({
199
+ jsonrpc: "2.0",
200
+ id,
201
+ error: {
202
+ code: JSON_RPC_ERROR_CODES.INTERNAL_ERROR,
203
+ message,
204
+ },
205
+ });
206
+ }
207
+ }
208
+ }
209
+ async function handleRequest(request, manifest, provider, onInitialize, logger) {
210
+ const { method, params, id } = request;
211
+ switch (method) {
212
+ case "initialize":
213
+ // Call onInitialize callback if provided (to receive credentials/config)
214
+ if (onInitialize) {
215
+ await onInitialize(params);
216
+ }
217
+ return {
218
+ jsonrpc: "2.0",
219
+ id,
220
+ result: manifest,
221
+ };
222
+ case "ping":
223
+ return {
224
+ jsonrpc: "2.0",
225
+ id,
226
+ result: "pong",
227
+ };
228
+ case "shutdown": {
229
+ logger.info("Shutdown requested");
230
+ // Write response directly with callback to ensure it's flushed before exit
231
+ const response = {
232
+ jsonrpc: "2.0",
233
+ id,
234
+ result: null,
235
+ };
236
+ process.stdout.write(`${JSON.stringify(response)}\n`, () => {
237
+ // Callback is called after the write is flushed to the OS
238
+ process.exit(0);
239
+ });
240
+ // Return a sentinel that handleLine will recognize and skip normal writeResponse
241
+ return null;
242
+ }
243
+ // Series metadata methods (scoped by content type)
244
+ case "metadata/series/search": {
245
+ const validationError = validateSearchParams(params);
246
+ if (validationError) {
247
+ return invalidParamsError(id, validationError);
248
+ }
249
+ return {
250
+ jsonrpc: "2.0",
251
+ id,
252
+ result: await provider.search(params),
253
+ };
254
+ }
255
+ case "metadata/series/get": {
256
+ const validationError = validateGetParams(params);
257
+ if (validationError) {
258
+ return invalidParamsError(id, validationError);
259
+ }
260
+ return {
261
+ jsonrpc: "2.0",
262
+ id,
263
+ result: await provider.get(params),
264
+ };
265
+ }
266
+ case "metadata/series/match": {
267
+ if (!provider.match) {
268
+ return {
269
+ jsonrpc: "2.0",
270
+ id,
271
+ error: {
272
+ code: JSON_RPC_ERROR_CODES.METHOD_NOT_FOUND,
273
+ message: "This plugin does not support match",
274
+ },
275
+ };
276
+ }
277
+ const validationError = validateMatchParams(params);
278
+ if (validationError) {
279
+ return invalidParamsError(id, validationError);
280
+ }
281
+ return {
282
+ jsonrpc: "2.0",
283
+ id,
284
+ result: await provider.match(params),
285
+ };
286
+ }
287
+ // Future: book metadata methods
288
+ // case "metadata/book/search":
289
+ // case "metadata/book/get":
290
+ // case "metadata/book/match":
291
+ default:
292
+ return {
293
+ jsonrpc: "2.0",
294
+ id,
295
+ error: {
296
+ code: JSON_RPC_ERROR_CODES.METHOD_NOT_FOUND,
297
+ message: `Method not found: ${method}`,
298
+ },
299
+ };
300
+ }
301
+ }
302
+ function writeResponse(response) {
303
+ // Write to stdout - this is the JSON-RPC channel
304
+ process.stdout.write(`${JSON.stringify(response)}\n`);
305
+ }
306
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAe,MAAM,aAAa,CAAC;AAQxD,OAAO,EACL,oBAAoB,GAIrB,MAAM,gBAAgB,CAAC;AAWxB;;GAEG;AACH,SAAS,oBAAoB,CAAC,MAAe,EAAE,MAAgB;IAC7D,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QAC5C,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,oBAAoB,EAAE,CAAC;IAC5D,CAAC;IACD,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC/B,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,0BAA0B,EAAE,CAAC;IAClE,CAAC;IAED,MAAM,GAAG,GAAG,MAAiC,CAAC;IAC9C,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC;QACzB,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YAC1C,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,KAAK,cAAc,EAAE,CAAC;QACpD,CAAC;QACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC9B,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,KAAK,mBAAmB,EAAE,CAAC;QACzD,CAAC;QACD,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YACxB,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,KAAK,kBAAkB,EAAE,CAAC;QACxD,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,SAAS,oBAAoB,CAAC,MAAe;IAC3C,OAAO,oBAAoB,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;AACjD,CAAC;AAED;;GAEG;AACH,SAAS,iBAAiB,CAAC,MAAe;IACxC,OAAO,oBAAoB,CAAC,MAAM,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC;AACtD,CAAC;AAED;;GAEG;AACH,SAAS,mBAAmB,CAAC,MAAe;IAC1C,OAAO,oBAAoB,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;AACjD,CAAC;AAED;;GAEG;AACH,SAAS,kBAAkB,CAAC,EAA0B,EAAE,KAAsB;IAC5E,OAAO;QACL,OAAO,EAAE,KAAK;QACd,EAAE;QACF,KAAK,EAAE;YACL,IAAI,EAAE,oBAAoB,CAAC,cAAc;YACzC,OAAO,EAAE,mBAAmB,KAAK,CAAC,OAAO,EAAE;YAC3C,IAAI,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE;SACb;KAClB,CAAC;AACJ,CAAC;AA4BD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAA8B;IACjE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC;IACxE,MAAM,MAAM,GAAG,YAAY,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;IAEtE,MAAM,CAAC,IAAI,CAAC,oBAAoB,QAAQ,CAAC,WAAW,KAAK,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;IAE7E,MAAM,EAAE,GAAG,eAAe,CAAC;QACzB,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,QAAQ,EAAE,KAAK;KAChB,CAAC,CAAC;IAEH,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;QACrB,KAAK,UAAU,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;QAClB,MAAM,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;QAC3C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,yBAAyB;IACzB,OAAO,CAAC,EAAE,CAAC,mBAAmB,EAAE,CAAC,KAAK,EAAE,EAAE;QACxC,MAAM,CAAC,KAAK,CAAC,oBAAoB,EAAE,KAAK,CAAC,CAAC;QAC1C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,EAAE,CAAC,oBAAoB,EAAE,CAAC,MAAM,EAAE,EAAE;QAC1C,MAAM,CAAC,KAAK,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;AACL,CAAC;AAED,gFAAgF;AAChF,uCAAuC;AACvC,gFAAgF;AAEhF;;GAEG;AACH,MAAM,UAAU,0BAA0B,CAAC,OAAoC;IAC7E,uCAAuC;IACvC,MAAM,UAAU,GAA0B;QACxC,GAAG,OAAO;QACV,QAAQ,EAAE;YACR,GAAG,OAAO,CAAC,QAAQ;YACnB,YAAY,EAAE;gBACZ,GAAG,OAAO,CAAC,QAAQ,CAAC,YAAY;gBAChC,gBAAgB,EAAE,CAAC,QAAQ,CAA0B;aACtD;SACF;KACF,CAAC;IACF,oBAAoB,CAAC,UAAU,CAAC,CAAC;AACnC,CAAC;AAkBD,gFAAgF;AAChF,0BAA0B;AAC1B,gFAAgF;AAEhF,KAAK,UAAU,UAAU,CACvB,IAAY,EACZ,QAAwB,EACxB,QAA0B,EAC1B,YAA8E,EAC9E,MAAc;IAEd,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,IAAI,CAAC,OAAO;QAAE,OAAO;IAErB,IAAI,EAAE,GAA2B,IAAI,CAAC;IAEtC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAmB,CAAC;QACtD,EAAE,GAAG,OAAO,CAAC,EAAE,CAAC;QAEhB,MAAM,CAAC,KAAK,CAAC,qBAAqB,OAAO,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;QAExE,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,CAAC,CAAC;QACxF,6DAA6D;QAC7D,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;YACtB,aAAa,CAAC,QAAQ,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,WAAW,EAAE,CAAC;YACjC,mBAAmB;YACnB,aAAa,CAAC;gBACZ,OAAO,EAAE,KAAK;gBACd,EAAE,EAAE,IAAI;gBACR,KAAK,EAAE;oBACL,IAAI,EAAE,oBAAoB,CAAC,WAAW;oBACtC,OAAO,EAAE,2BAA2B;iBACrC;aACF,CAAC,CAAC;QACL,CAAC;aAAM,IAAI,KAAK,YAAY,WAAW,EAAE,CAAC;YACxC,aAAa,CAAC;gBACZ,OAAO,EAAE,KAAK;gBACd,EAAE;gBACF,KAAK,EAAE,KAAK,CAAC,cAAc,EAAE;aAC9B,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;YACzE,MAAM,CAAC,KAAK,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC;YACtC,aAAa,CAAC;gBACZ,OAAO,EAAE,KAAK;gBACd,EAAE;gBACF,KAAK,EAAE;oBACL,IAAI,EAAE,oBAAoB,CAAC,cAAc;oBACzC,OAAO;iBACR;aACF,CAAC,CAAC;QACL,CAAC;IACH,CAAC;AACH,CAAC;AAED,KAAK,UAAU,aAAa,CAC1B,OAAuB,EACvB,QAAwB,EACxB,QAA0B,EAC1B,YAA8E,EAC9E,MAAc;IAEd,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC;IAEvC,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,YAAY;YACf,yEAAyE;YACzE,IAAI,YAAY,EAAE,CAAC;gBACjB,MAAM,YAAY,CAAC,MAA0B,CAAC,CAAC;YACjD,CAAC;YACD,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,EAAE;gBACF,MAAM,EAAE,QAAQ;aACjB,CAAC;QAEJ,KAAK,MAAM;YACT,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,EAAE;gBACF,MAAM,EAAE,MAAM;aACf,CAAC;QAEJ,KAAK,UAAU,CAAC,CAAC,CAAC;YAChB,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;YAClC,2EAA2E;YAC3E,MAAM,QAAQ,GAAoB;gBAChC,OAAO,EAAE,KAAK;gBACd,EAAE;gBACF,MAAM,EAAE,IAAI;aACb,CAAC;YACF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,GAAG,EAAE;gBACzD,0DAA0D;gBAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC,CAAC,CAAC;YACH,iFAAiF;YACjF,OAAO,IAAkC,CAAC;QAC5C,CAAC;QAED,mDAAmD;QACnD,KAAK,wBAAwB,CAAC,CAAC,CAAC;YAC9B,MAAM,eAAe,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC;YACrD,IAAI,eAAe,EAAE,CAAC;gBACpB,OAAO,kBAAkB,CAAC,EAAE,EAAE,eAAe,CAAC,CAAC;YACjD,CAAC;YACD,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,EAAE;gBACF,MAAM,EAAE,MAAM,QAAQ,CAAC,MAAM,CAAC,MAA8B,CAAC;aAC9D,CAAC;QACJ,CAAC;QAED,KAAK,qBAAqB,CAAC,CAAC,CAAC;YAC3B,MAAM,eAAe,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;YAClD,IAAI,eAAe,EAAE,CAAC;gBACpB,OAAO,kBAAkB,CAAC,EAAE,EAAE,eAAe,CAAC,CAAC;YACjD,CAAC;YACD,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,EAAE;gBACF,MAAM,EAAE,MAAM,QAAQ,CAAC,GAAG,CAAC,MAA2B,CAAC;aACxD,CAAC;QACJ,CAAC;QAED,KAAK,uBAAuB,CAAC,CAAC,CAAC;YAC7B,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;gBACpB,OAAO;oBACL,OAAO,EAAE,KAAK;oBACd,EAAE;oBACF,KAAK,EAAE;wBACL,IAAI,EAAE,oBAAoB,CAAC,gBAAgB;wBAC3C,OAAO,EAAE,oCAAoC;qBAC9C;iBACF,CAAC;YACJ,CAAC;YACD,MAAM,eAAe,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;YACpD,IAAI,eAAe,EAAE,CAAC;gBACpB,OAAO,kBAAkB,CAAC,EAAE,EAAE,eAAe,CAAC,CAAC;YACjD,CAAC;YACD,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,EAAE;gBACF,MAAM,EAAE,MAAM,QAAQ,CAAC,KAAK,CAAC,MAA6B,CAAC;aAC5D,CAAC;QACJ,CAAC;QAED,gCAAgC;QAChC,+BAA+B;QAC/B,4BAA4B;QAC5B,8BAA8B;QAE9B;YACE,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,EAAE;gBACF,KAAK,EAAE;oBACL,IAAI,EAAE,oBAAoB,CAAC,gBAAgB;oBAC3C,OAAO,EAAE,qBAAqB,MAAM,EAAE;iBACvC;aACF,CAAC;IACN,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,QAAyB;IAC9C,iDAAiD;IACjD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACxD,CAAC"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Capability interfaces - type-safe contracts for plugin capabilities
3
+ *
4
+ * Plugins declare which content types they support in their manifest's
5
+ * capabilities.metadataProvider array. The SDK automatically routes
6
+ * scoped methods (e.g., metadata/series/search) to the provider.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * // If manifest has capabilities.metadataProvider: ["series"],
11
+ * // the plugin must implement MetadataProvider
12
+ * const provider: MetadataProvider = {
13
+ * search: async (params) => { ... },
14
+ * get: async (params) => { ... },
15
+ * match: async (params) => { ... }, // optional
16
+ * };
17
+ * ```
18
+ */
19
+ import type { MetadataGetParams, MetadataMatchParams, MetadataMatchResponse, MetadataSearchParams, MetadataSearchResponse, PluginSeriesMetadata } from "./protocol.js";
20
+ /**
21
+ * Content types that a metadata provider can support.
22
+ * Plugins declare which types they support in capabilities.metadataProvider.
23
+ */
24
+ export type MetadataContentType = "series" | "book";
25
+ /**
26
+ * Interface for plugins that provide metadata.
27
+ *
28
+ * Plugins implementing this capability can:
29
+ * - Search for content by query
30
+ * - Get full metadata by external ID
31
+ * - Optionally match existing content to provider entries
32
+ *
33
+ * The same interface is used for both series and book metadata.
34
+ * The content type is determined by the method being called:
35
+ * - metadata/series/search -> provider.search()
36
+ * - metadata/book/search -> provider.search() (when book support is added)
37
+ */
38
+ export interface MetadataProvider {
39
+ /**
40
+ * Search for content matching a query
41
+ *
42
+ * @param params - Search parameters
43
+ * @returns Search results with relevance scores
44
+ */
45
+ search(params: MetadataSearchParams): Promise<MetadataSearchResponse>;
46
+ /**
47
+ * Get full metadata for a specific external ID
48
+ *
49
+ * @param params - Get parameters including external ID
50
+ * @returns Full metadata
51
+ */
52
+ get(params: MetadataGetParams): Promise<PluginSeriesMetadata>;
53
+ /**
54
+ * Find the best match for existing content (optional)
55
+ *
56
+ * This is used for auto-matching during library scans.
57
+ * If not implemented, Codex will use search() and pick the top result.
58
+ *
59
+ * @param params - Match parameters including title and hints
60
+ * @returns Best match with confidence score
61
+ */
62
+ match?(params: MetadataMatchParams): Promise<MetadataMatchResponse>;
63
+ }
64
+ /**
65
+ * Interface for plugins that sync reading progress (syncProvider: true)
66
+ * @future v2 - Methods will be defined when sync capability is implemented
67
+ */
68
+ export interface SyncProvider {
69
+ }
70
+ /**
71
+ * Interface for plugins that provide recommendations (recommendationProvider: true)
72
+ * @future v2 - Methods will be defined when recommendation capability is implemented
73
+ */
74
+ export interface RecommendationProvider {
75
+ }
76
+ /**
77
+ * Partial metadata provider - allows implementing only some methods
78
+ * Use this for testing or gradual implementation
79
+ */
80
+ export type PartialMetadataProvider = Partial<MetadataProvider>;
81
+ /**
82
+ * @deprecated Use MetadataProvider instead
83
+ */
84
+ export type SeriesMetadataProvider = MetadataProvider;
85
+ /**
86
+ * @deprecated Use PartialMetadataProvider instead
87
+ */
88
+ export type PartialSeriesMetadataProvider = PartialMetadataProvider;
89
+ //# sourceMappingURL=capabilities.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capabilities.d.ts","sourceRoot":"","sources":["../../src/types/capabilities.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EACV,iBAAiB,EACjB,mBAAmB,EACnB,qBAAqB,EACrB,oBAAoB,EACpB,sBAAsB,EACtB,oBAAoB,EACrB,MAAM,eAAe,CAAC;AAMvB;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,MAAM,CAAC;AAMpD;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;;OAKG;IACH,MAAM,CAAC,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;IAEtE;;;;;OAKG;IACH,GAAG,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAE9D;;;;;;;;OAQG;IACH,KAAK,CAAC,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;CACrE;AAMD;;;GAGG;AAEH,MAAM,WAAW,YAAY;CAAG;AAEhC;;;GAGG;AAEH,MAAM,WAAW,sBAAsB;CAAG;AAM1C;;;GAGG;AACH,MAAM,MAAM,uBAAuB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;AAMhE;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG,gBAAgB,CAAC;AAEtD;;GAEG;AACH,MAAM,MAAM,6BAA6B,GAAG,uBAAuB,CAAC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Capability interfaces - type-safe contracts for plugin capabilities
3
+ *
4
+ * Plugins declare which content types they support in their manifest's
5
+ * capabilities.metadataProvider array. The SDK automatically routes
6
+ * scoped methods (e.g., metadata/series/search) to the provider.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * // If manifest has capabilities.metadataProvider: ["series"],
11
+ * // the plugin must implement MetadataProvider
12
+ * const provider: MetadataProvider = {
13
+ * search: async (params) => { ... },
14
+ * get: async (params) => { ... },
15
+ * match: async (params) => { ... }, // optional
16
+ * };
17
+ * ```
18
+ */
19
+ export {};
20
+ //# sourceMappingURL=capabilities.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../../src/types/capabilities.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Re-export all types
3
+ */
4
+ export type { MetadataContentType, MetadataProvider, PartialMetadataProvider, PartialSeriesMetadataProvider, RecommendationProvider, SeriesMetadataProvider, SyncProvider, } from "./capabilities.js";
5
+ export type { CredentialField, PluginCapabilities, PluginManifest } from "./manifest.js";
6
+ export { hasBookMetadataProvider, hasSeriesMetadataProvider } from "./manifest.js";
7
+ export type { AlternateTitle, ExternalLink, ExternalLinkType, ExternalRating, MetadataGetParams, MetadataMatchParams, MetadataMatchResponse, MetadataSearchParams, MetadataSearchResponse, PluginSeriesMetadata, ReadingDirection, SearchResult, SearchResultPreview, SeriesStatus, } from "./protocol.js";
8
+ export * from "./rpc.js";
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,YAAY,EAEV,mBAAmB,EACnB,gBAAgB,EAChB,uBAAuB,EACvB,6BAA6B,EAC7B,sBAAsB,EAEtB,sBAAsB,EACtB,YAAY,GACb,MAAM,mBAAmB,CAAC;AAG3B,YAAY,EAAE,eAAe,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACzF,OAAO,EAAE,uBAAuB,EAAE,yBAAyB,EAAE,MAAM,eAAe,CAAC;AAGnF,YAAY,EACV,cAAc,EACd,YAAY,EACZ,gBAAgB,EAChB,cAAc,EACd,iBAAiB,EACjB,mBAAmB,EACnB,qBAAqB,EACrB,oBAAoB,EACpB,sBAAsB,EACtB,oBAAoB,EACpB,gBAAgB,EAChB,YAAY,EACZ,mBAAmB,EACnB,YAAY,GACb,MAAM,eAAe,CAAC;AACvB,cAAc,UAAU,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Re-export all types
3
+ */
4
+ export { hasBookMetadataProvider, hasSeriesMetadataProvider } from "./manifest.js";
5
+ export * from "./rpc.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAiBH,OAAO,EAAE,uBAAuB,EAAE,yBAAyB,EAAE,MAAM,eAAe,CAAC;AAmBnF,cAAc,UAAU,CAAC"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Plugin manifest types - describes plugin capabilities and requirements
3
+ */
4
+ import type { MetadataContentType } from "./capabilities.js";
5
+ /**
6
+ * Credential field configuration for admin UI
7
+ */
8
+ export interface CredentialField {
9
+ /** Unique key for this credential (used in environment variables) */
10
+ key: string;
11
+ /** Human-readable label for the UI */
12
+ label: string;
13
+ /** Help text explaining where to get this credential */
14
+ description?: string;
15
+ /** Whether this credential is required */
16
+ required: boolean;
17
+ /** Whether to mask this value in the UI (for passwords/API keys) */
18
+ sensitive: boolean;
19
+ /** Input type for the UI */
20
+ type: "text" | "password" | "url";
21
+ /** Placeholder text */
22
+ placeholder?: string;
23
+ }
24
+ /**
25
+ * Plugin capabilities
26
+ */
27
+ export interface PluginCapabilities {
28
+ /**
29
+ * Content types this plugin can provide metadata for.
30
+ * E.g., ["series"] or ["series", "book"]
31
+ */
32
+ metadataProvider?: MetadataContentType[];
33
+ /** Can sync reading progress with external service */
34
+ syncProvider?: boolean;
35
+ /** Can provide recommendations */
36
+ recommendationProvider?: boolean;
37
+ }
38
+ /**
39
+ * Plugin manifest returned by the `initialize` method
40
+ */
41
+ export interface PluginManifest {
42
+ /** Unique plugin identifier (lowercase, alphanumeric, hyphens) */
43
+ name: string;
44
+ /** Human-readable name for UI display */
45
+ displayName: string;
46
+ /** Plugin version (semver) */
47
+ version: string;
48
+ /** Short description of what the plugin does */
49
+ description: string;
50
+ /** Author name or organization */
51
+ author: string;
52
+ /** Homepage URL (documentation, source code) */
53
+ homepage?: string;
54
+ /** Icon URL (optional, for UI display) */
55
+ icon?: string;
56
+ /** Protocol version this plugin implements */
57
+ protocolVersion: "1.0";
58
+ /** What this plugin can do */
59
+ capabilities: PluginCapabilities;
60
+ /** Credentials required from admin */
61
+ requiredCredentials?: CredentialField[];
62
+ }
63
+ /**
64
+ * Type guard to check if manifest declares series metadata provider capability
65
+ */
66
+ export declare function hasSeriesMetadataProvider(manifest: PluginManifest): manifest is PluginManifest & {
67
+ capabilities: {
68
+ metadataProvider: MetadataContentType[];
69
+ };
70
+ };
71
+ /**
72
+ * Type guard to check if manifest declares book metadata provider capability
73
+ */
74
+ export declare function hasBookMetadataProvider(manifest: PluginManifest): manifest is PluginManifest & {
75
+ capabilities: {
76
+ metadataProvider: MetadataContentType[];
77
+ };
78
+ };
79
+ /**
80
+ * @deprecated Use PluginCapabilities with metadataProvider array instead
81
+ */
82
+ export interface LegacyPluginCapabilities {
83
+ /** @deprecated Use metadataProvider: ["series"] instead */
84
+ seriesMetadataProvider?: boolean;
85
+ syncProvider?: boolean;
86
+ recommendationProvider?: boolean;
87
+ }
88
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/types/manifest.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAE7D;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,qEAAqE;IACrE,GAAG,EAAE,MAAM,CAAC;IACZ,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,wDAAwD;IACxD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0CAA0C;IAC1C,QAAQ,EAAE,OAAO,CAAC;IAClB,oEAAoE;IACpE,SAAS,EAAE,OAAO,CAAC;IACnB,4BAA4B;IAC5B,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,KAAK,CAAC;IAClC,uBAAuB;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,gBAAgB,CAAC,EAAE,mBAAmB,EAAE,CAAC;IACzC,sDAAsD;IACtD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,kCAAkC;IAClC,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,kEAAkE;IAClE,IAAI,EAAE,MAAM,CAAC;IACb,yCAAyC;IACzC,WAAW,EAAE,MAAM,CAAC;IACpB,8BAA8B;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,gDAAgD;IAChD,WAAW,EAAE,MAAM,CAAC;IACpB,kCAAkC;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,gDAAgD;IAChD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0CAA0C;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,8CAA8C;IAC9C,eAAe,EAAE,KAAK,CAAC;IAEvB,8BAA8B;IAC9B,YAAY,EAAE,kBAAkB,CAAC;IAEjC,sCAAsC;IACtC,mBAAmB,CAAC,EAAE,eAAe,EAAE,CAAC;CACzC;AAMD;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,cAAc,GAAG,QAAQ,IAAI,cAAc,GAAG;IAChG,YAAY,EAAE;QAAE,gBAAgB,EAAE,mBAAmB,EAAE,CAAA;KAAE,CAAC;CAC3D,CAKA;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,cAAc,GAAG,QAAQ,IAAI,cAAc,GAAG;IAC9F,YAAY,EAAE;QAAE,gBAAgB,EAAE,mBAAmB,EAAE,CAAA;KAAE,CAAC;CAC3D,CAKA;AAMD;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,2DAA2D;IAC3D,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC"}