@quanthea/plugin-kit 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +63 -0
- package/checks.d.ts +13 -0
- package/chunk-3ayrhcmg.js +5 -0
- package/connector-kind.d.ts +128 -0
- package/errors.d.ts +34 -0
- package/frame-builder.d.ts +38 -0
- package/frames.d.ts +62 -0
- package/host.d.ts +12 -0
- package/http-address.d.ts +18 -0
- package/http.d.ts +91 -0
- package/index.d.ts +21 -0
- package/index.js +7 -0
- package/kit.d.ts +37 -0
- package/languages.d.ts +16 -0
- package/package.json +41 -0
- package/queries.d.ts +151 -0
- package/schema.d.ts +58 -0
- package/series-frames.d.ts +55 -0
- package/testing.d.ts +36 -0
- package/testing.js +642 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Josep Boix Requesens
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# @quanthea/plugin-kit
|
|
2
|
+
|
|
3
|
+
The kit a [quanthea](https://github.com/jboix/quanthea) connector plugin is written against. A
|
|
4
|
+
plugin adds connector kinds, such as a new database, to a quanthea server.
|
|
5
|
+
|
|
6
|
+
The kit is in beta: version 0.x, kit version 0.
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
bun add -d @quanthea/plugin-kit@^0.1.0
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
It is a development dependency. A plugin imports only types from it, and quanthea passes the live
|
|
15
|
+
kit to the plugin when it loads it, so the bundle carries none of the kit's code.
|
|
16
|
+
|
|
17
|
+
## Write a plugin
|
|
18
|
+
|
|
19
|
+
The plugin is one bundled ES module. It exports the kit version it is built for and, as default, a
|
|
20
|
+
function that receives the kit and returns its kinds:
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
import type { ConnectorKit } from '@quanthea/plugin-kit';
|
|
24
|
+
|
|
25
|
+
export const kitVersion = 0;
|
|
26
|
+
|
|
27
|
+
export default function plugin(kit: ConnectorKit) {
|
|
28
|
+
return [kit.defineConnector({ kind: 'example', configSchema: kit.z.object({ … }), … })];
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
- Build the schemas with `kit.z` and throw `kit.ConnectorError`: they are quanthea's own.
|
|
33
|
+
- Name the package `quanthea-plugin-<name>` or `@scope/quanthea-plugin-<name>`, with the
|
|
34
|
+
`quanthea-plugin` keyword.
|
|
35
|
+
- Add the manifest field to `package.json`: `"quanthea": { "kitVersion": 0, "main": "dist/plugin.js" }`.
|
|
36
|
+
|
|
37
|
+
[Publishing a plugin](https://github.com/jboix/quanthea/blob/main/docs/connectors.md#publishing-a-plugin)
|
|
38
|
+
covers the bundle, the manifest and publishing. The
|
|
39
|
+
[SQLite example](https://github.com/jboix/quanthea/tree/main/examples/quanthea-plugin-sqlite) is a
|
|
40
|
+
complete plugin to start from.
|
|
41
|
+
|
|
42
|
+
## Test a plugin
|
|
43
|
+
|
|
44
|
+
`@quanthea/plugin-kit/testing` runs under `bun test`:
|
|
45
|
+
|
|
46
|
+
- `createTestKit()` returns the live kit, the same one quanthea passes at load.
|
|
47
|
+
- `testConnectorConformance(kind, fixture)` registers the tests every kind passes: the static
|
|
48
|
+
checks quanthea runs at install and load, then queries against a real source.
|
|
49
|
+
|
|
50
|
+
## Versions
|
|
51
|
+
|
|
52
|
+
The kit's major version equals `kitVersion`. While the kit is in 0.x:
|
|
53
|
+
|
|
54
|
+
- A **minor** version, such as 0.2.0, adds to the kit.
|
|
55
|
+
- A **patch** version, such as 0.1.1, fixes it.
|
|
56
|
+
|
|
57
|
+
npm's caret stays within one minor version on 0.x: `^0.1.0` takes the 0.1.x fixes, and moving to
|
|
58
|
+
0.2.0 is your choice. At 1.0, the kit becomes 1.0.0 and `kitVersion` becomes 1, and quanthea stops
|
|
59
|
+
loading plugins built for kit version 0.
|
|
60
|
+
|
|
61
|
+
## Licence
|
|
62
|
+
|
|
63
|
+
MIT
|
package/checks.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The static checks of a connector kind: what it declares, without a source. The loader runs them
|
|
3
|
+
* on every plugin's kinds at startup, the installer before it keeps a plugin, and the conformance
|
|
4
|
+
* suite in every kind's tests, so a kind that passes its own tests passes the loader. A plugin may
|
|
5
|
+
* return an object it did not build with `defineConnector`, so nothing is taken for granted.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Everything wrong with what a kind declares.
|
|
9
|
+
*
|
|
10
|
+
* @param kind - The kind, as a plugin returned it.
|
|
11
|
+
* @returns The problems, empty when it passes.
|
|
12
|
+
*/
|
|
13
|
+
export declare function kindProblems(kind: unknown): string[];
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/** The contract of a connector kind: what it declares, and what an open connection can do. */
|
|
2
|
+
import type { z } from 'zod';
|
|
3
|
+
import type { Frame } from './frames.js';
|
|
4
|
+
import { type BoundQuery, type ExecutionContext, type QueryLanguage, type SqlDialect, type SqlPlaceholderStyle, type SqlRowLimit } from './queries.js';
|
|
5
|
+
import type { FieldReference, HealthReport, SampleResult, SchemaSnapshot } from './schema.js';
|
|
6
|
+
/**
|
|
7
|
+
* An open connection to one source. The core calls it only with bound queries and guardrails it has
|
|
8
|
+
* already checked, and passes every result through its own checks.
|
|
9
|
+
*/
|
|
10
|
+
export interface ConnectorInstance {
|
|
11
|
+
/**
|
|
12
|
+
* Checks that the source answers and the credentials work.
|
|
13
|
+
*
|
|
14
|
+
* @param signal - Aborted when the caller gives up.
|
|
15
|
+
* @returns The health report. A failed check is a report with `ok: false`, not an error.
|
|
16
|
+
*/
|
|
17
|
+
test(signal: AbortSignal): Promise<HealthReport>;
|
|
18
|
+
/**
|
|
19
|
+
* Reads the shape of the source: entities and fields, never values.
|
|
20
|
+
*
|
|
21
|
+
* @param signal - Aborted when the caller gives up.
|
|
22
|
+
* @returns The schema snapshot.
|
|
23
|
+
* @throws {ConnectorError} When the source cannot be read.
|
|
24
|
+
*/
|
|
25
|
+
describe(signal: AbortSignal): Promise<SchemaSnapshot>;
|
|
26
|
+
/**
|
|
27
|
+
* Reads distinct values of one field.
|
|
28
|
+
*
|
|
29
|
+
* @param field - The field, as named in the schema snapshot.
|
|
30
|
+
* @param limit - How many values to return at most.
|
|
31
|
+
* @param signal - Aborted when the caller gives up.
|
|
32
|
+
* @returns The values, and whether there are more.
|
|
33
|
+
* @throws {ConnectorError} When the field does not exist or the source fails.
|
|
34
|
+
*/
|
|
35
|
+
sampleValues(field: FieldReference, limit: number, signal: AbortSignal): Promise<SampleResult>;
|
|
36
|
+
/**
|
|
37
|
+
* Runs a bound query.
|
|
38
|
+
*
|
|
39
|
+
* @param query - The query, in the connector kind's language.
|
|
40
|
+
* @param context - The time range, row limit and abort signal to respect.
|
|
41
|
+
* @returns One or more frames named `context.refId`.
|
|
42
|
+
* @throws {ConnectorError} When the query fails, times out or is aborted.
|
|
43
|
+
*/
|
|
44
|
+
execute(query: BoundQuery, context: ExecutionContext): Promise<Frame[]>;
|
|
45
|
+
/**
|
|
46
|
+
* Releases pooled connections. The core calls it when the connector is changed or deleted.
|
|
47
|
+
*
|
|
48
|
+
* @returns When everything is released.
|
|
49
|
+
*/
|
|
50
|
+
close(): Promise<void>;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* A kind's logo, so people tell kinds apart at a glance: one SVG path on a 24×24 grid, filled with
|
|
54
|
+
* one colour. It is data, not markup: the app draws it.
|
|
55
|
+
*/
|
|
56
|
+
export interface ConnectorIcon {
|
|
57
|
+
/** The path data, the `d` attribute of an SVG `path`. */
|
|
58
|
+
readonly path: string;
|
|
59
|
+
/** The fill colour, as `#rrggbb`. */
|
|
60
|
+
readonly color: string;
|
|
61
|
+
}
|
|
62
|
+
/** What {@link ConnectorKind.open} receives: the parsed configuration and credentials. */
|
|
63
|
+
export interface OpenOptions<Config, Secret> {
|
|
64
|
+
/** The configuration, parsed with the kind's config schema. */
|
|
65
|
+
readonly config: Config;
|
|
66
|
+
/** The credentials, parsed with the kind's secret schema. */
|
|
67
|
+
readonly secret: Secret;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* A kind of data source, such as PostgreSQL. It declares its settings as Zod schemas, from which the
|
|
71
|
+
* app builds its forms, and opens connections.
|
|
72
|
+
*/
|
|
73
|
+
export interface ConnectorKind<ConfigSchema extends z.ZodType = z.ZodType, SecretSchema extends z.ZodType = z.ZodType> {
|
|
74
|
+
/** A stable identifier, lowercase with dashes, such as `postgres`. Stored with each connector. */
|
|
75
|
+
readonly kind: string;
|
|
76
|
+
/** The name shown to people, such as `PostgreSQL`. */
|
|
77
|
+
readonly displayName: string;
|
|
78
|
+
/** The kind's logo. Without one, the app shows the first letters of its name. */
|
|
79
|
+
readonly icon?: ConnectorIcon;
|
|
80
|
+
/** Other names the add form finds the kind by, such as `timescaledb` for PostgreSQL. */
|
|
81
|
+
readonly aliases?: readonly string[];
|
|
82
|
+
/** The language of this kind's query templates. The core binds variables for it. */
|
|
83
|
+
readonly language: QueryLanguage;
|
|
84
|
+
/** The SQL dialect, which a `sql` kind must declare: how the core binds its templates. */
|
|
85
|
+
readonly dialect?: SqlDialect;
|
|
86
|
+
/** For the `ansi` dialect: how the source writes a placeholder. `?` when not given. */
|
|
87
|
+
readonly placeholders?: SqlPlaceholderStyle;
|
|
88
|
+
/** For the `ansi` dialect: how the source limits rows. `fetch` when not given. */
|
|
89
|
+
readonly rowLimit?: SqlRowLimit;
|
|
90
|
+
/**
|
|
91
|
+
* Everything but the credentials: host, database, TLS options. Stored in plain text and shown to
|
|
92
|
+
* admins. Give each field a title and a description with `.meta()`; the form is built from them.
|
|
93
|
+
*/
|
|
94
|
+
readonly configSchema: ConfigSchema;
|
|
95
|
+
/** The credentials. Stored encrypted and never returned by the API. */
|
|
96
|
+
readonly secretSchema: SecretSchema;
|
|
97
|
+
/**
|
|
98
|
+
* How to get each shape of data in this kind's language, for the agent: about data, never about
|
|
99
|
+
* charts. Adding a connector kind means adding its guide, with no chart recipe changing.
|
|
100
|
+
*/
|
|
101
|
+
readonly queryGuide?: string;
|
|
102
|
+
/**
|
|
103
|
+
* Says where a connector points, shown under its name, such as
|
|
104
|
+
* `postgres://dash_ro@orders-replica:5432/orders`. It must not include credentials.
|
|
105
|
+
*
|
|
106
|
+
* @param config - The parsed configuration.
|
|
107
|
+
* @returns One line.
|
|
108
|
+
*/
|
|
109
|
+
describeTarget?(config: z.output<ConfigSchema>): string;
|
|
110
|
+
/**
|
|
111
|
+
* Opens a connection. It must not contact the source; the first call does.
|
|
112
|
+
*
|
|
113
|
+
* @param options - The parsed configuration and credentials.
|
|
114
|
+
* @returns The connection.
|
|
115
|
+
*/
|
|
116
|
+
open(options: OpenOptions<z.output<ConfigSchema>, z.output<SecretSchema>>): ConnectorInstance;
|
|
117
|
+
}
|
|
118
|
+
/** A connector kind whatever its schemas, as the registry holds them. */
|
|
119
|
+
export type AnyConnectorKind = ConnectorKind<z.ZodType, z.ZodType>;
|
|
120
|
+
/**
|
|
121
|
+
* Declares a connector kind. It checks the identifier and keeps the schema types for `open`.
|
|
122
|
+
*
|
|
123
|
+
* @param definition - The kind.
|
|
124
|
+
* @returns The same kind.
|
|
125
|
+
* @throws {Error} When the identifier is not lowercase letters, digits and dashes, a SQL kind
|
|
126
|
+
* declares no dialect, or the icon is malformed.
|
|
127
|
+
*/
|
|
128
|
+
export declare function defineConnector<ConfigSchema extends z.ZodType, SecretSchema extends z.ZodType>(definition: ConnectorKind<ConfigSchema, SecretSchema>): ConnectorKind<ConfigSchema, SecretSchema>;
|
package/errors.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/** The one error type connectors throw. */
|
|
2
|
+
/** Why a connector call can fail. */
|
|
3
|
+
declare const connectorErrorCodes: readonly ["unreachable", "authentication", "permission", "syntax", "not_found", "timeout", "rejected", "internal"];
|
|
4
|
+
/** Why a connector call failed. The gate and the UI switch on this. */
|
|
5
|
+
export type ConnectorErrorCode = (typeof connectorErrorCodes)[number];
|
|
6
|
+
/**
|
|
7
|
+
* A failed connector call. `message` is the source's own text and may quote data, such as a value in
|
|
8
|
+
* a type error; only people allowed to see the data get it. `safeMessage` must quote no data: the
|
|
9
|
+
* model receives it whatever the connector's access level.
|
|
10
|
+
*/
|
|
11
|
+
export declare class ConnectorError extends Error {
|
|
12
|
+
/** Why the call failed. */
|
|
13
|
+
readonly code: ConnectorErrorCode;
|
|
14
|
+
/** A description that quotes no values from the source. Identifiers are fine. */
|
|
15
|
+
readonly safeMessage: string;
|
|
16
|
+
/**
|
|
17
|
+
* Creates the error.
|
|
18
|
+
*
|
|
19
|
+
* @param code - Why the call failed.
|
|
20
|
+
* @param safeMessage - A description that quotes no values from the source.
|
|
21
|
+
* @param message - The source's own message, which may quote values. Defaults to `safeMessage`.
|
|
22
|
+
* @param options - The underlying error, as `cause`.
|
|
23
|
+
*/
|
|
24
|
+
constructor(code: ConnectorErrorCode, safeMessage: string, message?: string, options?: ErrorOptions);
|
|
25
|
+
/**
|
|
26
|
+
* Whether a value is a connector error: an instance of this class, or of another copy of it, by
|
|
27
|
+
* the brand, with a known code and a safe message. So `instanceof` holds across copies.
|
|
28
|
+
*
|
|
29
|
+
* @param value - The value.
|
|
30
|
+
* @returns `true` for a connector error.
|
|
31
|
+
*/
|
|
32
|
+
static [Symbol.hasInstance](value: unknown): boolean;
|
|
33
|
+
}
|
|
34
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/** Builds a frame row by row, stopping at the row limit. */
|
|
2
|
+
import type { Field, Frame } from './frames.js';
|
|
3
|
+
/** Collects rows into a frame. */
|
|
4
|
+
export interface FrameBuilder {
|
|
5
|
+
/**
|
|
6
|
+
* Adds a row. Past the row limit the row is dropped and the frame is marked truncated.
|
|
7
|
+
*
|
|
8
|
+
* @param row - One value per field, in field order.
|
|
9
|
+
* @returns `false` when the row was dropped because the frame is full: stop reading.
|
|
10
|
+
*/
|
|
11
|
+
add(row: readonly unknown[]): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Finishes the frame.
|
|
14
|
+
*
|
|
15
|
+
* @param durationMs - How long the query took.
|
|
16
|
+
* @returns The frame.
|
|
17
|
+
*/
|
|
18
|
+
build(durationMs: number): Frame;
|
|
19
|
+
}
|
|
20
|
+
/** What a frame builder needs to know. */
|
|
21
|
+
export interface FrameBuilderOptions {
|
|
22
|
+
/** The frame name the query was given (`ExecutionContext.refId`). */
|
|
23
|
+
readonly refId: string;
|
|
24
|
+
/** The fields, in column order. */
|
|
25
|
+
readonly fields: readonly Field[];
|
|
26
|
+
/** The row limit (`ExecutionContext.maxRows`). */
|
|
27
|
+
readonly maxRows: number;
|
|
28
|
+
/** A name for the frame, such as a series name. */
|
|
29
|
+
readonly name?: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Creates a frame builder. Read one row more than the limit so the builder can tell the frame was
|
|
33
|
+
* truncated.
|
|
34
|
+
*
|
|
35
|
+
* @param options - The frame name, fields and row limit.
|
|
36
|
+
* @returns The builder.
|
|
37
|
+
*/
|
|
38
|
+
export declare function createFrameBuilder(options: FrameBuilderOptions): FrameBuilder;
|
package/frames.d.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/** Result frames: the column-based format every connector returns and the browser renders. */
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
/** The value types a field can hold. Times are Unix epoch milliseconds. */
|
|
4
|
+
export declare const fieldTypes: readonly ["time", "number", "string", "boolean"];
|
|
5
|
+
/** A field value type. */
|
|
6
|
+
export type FieldType = (typeof fieldTypes)[number];
|
|
7
|
+
/** Validates a field: one column of a frame. */
|
|
8
|
+
export declare const fieldSchema: z.ZodObject<{
|
|
9
|
+
name: z.ZodString;
|
|
10
|
+
type: z.ZodEnum<{
|
|
11
|
+
string: "string";
|
|
12
|
+
number: "number";
|
|
13
|
+
boolean: "boolean";
|
|
14
|
+
time: "time";
|
|
15
|
+
}>;
|
|
16
|
+
labels: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
17
|
+
unit: z.ZodOptional<z.ZodString>;
|
|
18
|
+
}, z.core.$strip>;
|
|
19
|
+
/** One column of a frame: its name, value type, and for time series, the series labels. */
|
|
20
|
+
export type Field = z.infer<typeof fieldSchema>;
|
|
21
|
+
/** Validates the shape of a frame. {@link frameProblems} also checks the values. */
|
|
22
|
+
export declare const frameSchema: z.ZodObject<{
|
|
23
|
+
refId: z.ZodString;
|
|
24
|
+
name: z.ZodOptional<z.ZodString>;
|
|
25
|
+
fields: z.ZodArray<z.ZodObject<{
|
|
26
|
+
name: z.ZodString;
|
|
27
|
+
type: z.ZodEnum<{
|
|
28
|
+
string: "string";
|
|
29
|
+
number: "number";
|
|
30
|
+
boolean: "boolean";
|
|
31
|
+
time: "time";
|
|
32
|
+
}>;
|
|
33
|
+
labels: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
34
|
+
unit: z.ZodOptional<z.ZodString>;
|
|
35
|
+
}, z.core.$strip>>;
|
|
36
|
+
values: z.ZodArray<z.ZodArray<z.ZodUnknown>>;
|
|
37
|
+
meta: z.ZodObject<{
|
|
38
|
+
rowCount: z.ZodNumber;
|
|
39
|
+
truncated: z.ZodBoolean;
|
|
40
|
+
durationMs: z.ZodNumber;
|
|
41
|
+
}, z.core.$strip>;
|
|
42
|
+
}, z.core.$strip>;
|
|
43
|
+
/**
|
|
44
|
+
* A query result in columns: `values[i]` holds the values of `fields[i]`, one per row. A missing
|
|
45
|
+
* value is `null`.
|
|
46
|
+
*/
|
|
47
|
+
export type Frame = z.infer<typeof frameSchema>;
|
|
48
|
+
/**
|
|
49
|
+
* Lists everything wrong with a frame: its shape, column lengths, and value types.
|
|
50
|
+
*
|
|
51
|
+
* @param frame - The frame to check, as received.
|
|
52
|
+
* @returns One sentence per problem, empty when the frame is valid.
|
|
53
|
+
*/
|
|
54
|
+
export declare function frameProblems(frame: unknown): string[];
|
|
55
|
+
/**
|
|
56
|
+
* Orders two values of a frame: numbers by value, anything else as text.
|
|
57
|
+
*
|
|
58
|
+
* @param first - One value.
|
|
59
|
+
* @param second - The other.
|
|
60
|
+
* @returns Negative, zero or positive.
|
|
61
|
+
*/
|
|
62
|
+
export declare function compareFrameValues(first: unknown, second: unknown): number;
|
package/host.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type ConnectorKit } from './kit.js';
|
|
2
|
+
/** The kit every plugin receives. */
|
|
3
|
+
export declare const hostKit: ConnectorKit;
|
|
4
|
+
export { kindProblems } from './checks.js';
|
|
5
|
+
export { type AnyConnectorKind, type ConnectorIcon, type ConnectorInstance, type ConnectorKind, defineConnector, } from './connector-kind.js';
|
|
6
|
+
export { ConnectorError, type ConnectorErrorCode } from './errors.js';
|
|
7
|
+
export { createFrameBuilder } from './frame-builder.js';
|
|
8
|
+
export { createHttpClient, type HttpClient, type HttpResponse } from './http.js';
|
|
9
|
+
export { kitVersion } from './kit.js';
|
|
10
|
+
export { type BoundQuery, type ExecutionContext, type HttpField, type HttpQuery, type LogqlQuery, type MongodbQuery, type PromqlQuery, type QueryLanguage, type RedisQuery, type SearchQuery, type SqlDialect, type SqlParameter, type SqlPlaceholderStyle, type SqlQuery, type SqlRowLimit, sqlDialects, type TimeRange, } from './queries.js';
|
|
11
|
+
export type { FieldReference, HealthReport, SampleResult, SchemaEntity, SchemaField, SchemaSnapshot, } from './schema.js';
|
|
12
|
+
export { type SeriesData, seriesFrames } from './series-frames.js';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether an address is a cloud metadata address.
|
|
3
|
+
*
|
|
4
|
+
* @param address - An IP address, or a URL host with IPv6 in brackets.
|
|
5
|
+
* @returns `true` for a metadata address, `false` for any other address or a name.
|
|
6
|
+
*/
|
|
7
|
+
export declare function isMetadataAddress(address: string): boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Checks that a URL does not point to a cloud metadata address, by its host and, for a name, by
|
|
10
|
+
* the addresses it resolves to. A name that does not resolve passes: the request then fails as
|
|
11
|
+
* unreachable.
|
|
12
|
+
*
|
|
13
|
+
* @param url - The URL about to be called.
|
|
14
|
+
* @param sourceName - The source, for the message, such as `ClickHouse`.
|
|
15
|
+
* @returns Once the address is checked.
|
|
16
|
+
* @throws {ConnectorError} `rejected` when the host is or resolves to a metadata address.
|
|
17
|
+
*/
|
|
18
|
+
export declare function checkDestination(url: URL, sourceName: string): Promise<void>;
|
package/http.d.ts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/** How a client reaches its source. */
|
|
2
|
+
export interface HttpClientOptions {
|
|
3
|
+
/** The base URL. Its origin is the only one called; its path prefixes every request path. */
|
|
4
|
+
readonly baseUrl: string;
|
|
5
|
+
/** The source, in error messages, such as `ClickHouse`. */
|
|
6
|
+
readonly sourceName: string;
|
|
7
|
+
/** Headers sent with every request, such as `Authorization`. */
|
|
8
|
+
readonly headers?: Readonly<Record<string, string>>;
|
|
9
|
+
/** Whether to check the server certificate. Defaults to `true`. */
|
|
10
|
+
readonly verifyTls?: boolean;
|
|
11
|
+
/** The longest a request may take, body included, in milliseconds. Defaults to 120 seconds. */
|
|
12
|
+
readonly timeoutMs?: number;
|
|
13
|
+
/** The most bytes of a body read. Defaults to 64 MiB. */
|
|
14
|
+
readonly maxBytes?: number;
|
|
15
|
+
}
|
|
16
|
+
/** The methods a connector sends. */
|
|
17
|
+
type HttpMethod = 'GET' | 'POST' | 'DELETE';
|
|
18
|
+
/** One request. */
|
|
19
|
+
export interface HttpRequest {
|
|
20
|
+
/** The method. Defaults to `GET`. */
|
|
21
|
+
readonly method?: HttpMethod;
|
|
22
|
+
/**
|
|
23
|
+
* The path under the base URL, starting with `/`, or an absolute URL on the same origin, such as
|
|
24
|
+
* a link to the next page the source returned.
|
|
25
|
+
*/
|
|
26
|
+
readonly path: string;
|
|
27
|
+
/** Query string parameters; an array value repeats the parameter. */
|
|
28
|
+
readonly query?: Readonly<Record<string, string | readonly string[]>>;
|
|
29
|
+
/** Headers for this request, added to the client's. */
|
|
30
|
+
readonly headers?: Readonly<Record<string, string>>;
|
|
31
|
+
/** The body of a POST. */
|
|
32
|
+
readonly body?: string;
|
|
33
|
+
/** Aborts the request and the reading of its body. */
|
|
34
|
+
readonly signal: AbortSignal;
|
|
35
|
+
}
|
|
36
|
+
/** A response whose body is read at most once, within the byte cap. */
|
|
37
|
+
export interface HttpResponse {
|
|
38
|
+
/** The HTTP status. */
|
|
39
|
+
readonly status: number;
|
|
40
|
+
/** Whether the status is 2xx. */
|
|
41
|
+
readonly ok: boolean;
|
|
42
|
+
/** The response headers. */
|
|
43
|
+
readonly headers: Headers;
|
|
44
|
+
/**
|
|
45
|
+
* Reads the body as text.
|
|
46
|
+
*
|
|
47
|
+
* @returns The text.
|
|
48
|
+
* @throws {ConnectorError} Past the byte cap, at the timeout or when the connection fails.
|
|
49
|
+
*/
|
|
50
|
+
text(): Promise<string>;
|
|
51
|
+
/**
|
|
52
|
+
* Reads the body as JSON.
|
|
53
|
+
*
|
|
54
|
+
* @returns The parsed value.
|
|
55
|
+
* @throws {ConnectorError} When the body is not JSON, and as {@link HttpResponse.text}.
|
|
56
|
+
*/
|
|
57
|
+
json(): Promise<unknown>;
|
|
58
|
+
/**
|
|
59
|
+
* Reads the body line by line, without the line ends. Stopping early closes the connection.
|
|
60
|
+
*
|
|
61
|
+
* @returns The lines.
|
|
62
|
+
* @throws {ConnectorError} As {@link HttpResponse.text}.
|
|
63
|
+
*/
|
|
64
|
+
lines(): AsyncGenerator<string>;
|
|
65
|
+
/**
|
|
66
|
+
* Leaves the body unread and closes the connection.
|
|
67
|
+
*
|
|
68
|
+
* @returns Once the body is cancelled.
|
|
69
|
+
*/
|
|
70
|
+
cancel(): Promise<void>;
|
|
71
|
+
}
|
|
72
|
+
/** Sends requests to one source. */
|
|
73
|
+
export interface HttpClient {
|
|
74
|
+
/**
|
|
75
|
+
* Sends a request.
|
|
76
|
+
*
|
|
77
|
+
* @param request - The request.
|
|
78
|
+
* @returns The response, whatever its status.
|
|
79
|
+
* @throws {ConnectorError} `unreachable` when the connection fails, `timeout` when the signal or
|
|
80
|
+
* the timeout fires, `rejected` for a redirect to another origin or a metadata address.
|
|
81
|
+
*/
|
|
82
|
+
request(request: HttpRequest): Promise<HttpResponse>;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Creates a client for one source.
|
|
86
|
+
*
|
|
87
|
+
* @param options - The base URL, headers, TLS setting and limits.
|
|
88
|
+
* @returns The client.
|
|
89
|
+
*/
|
|
90
|
+
export declare function createHttpClient(options: HttpClientOptions): HttpClient;
|
|
91
|
+
export {};
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The public kit: the types a connector plugin is written against, and the kit version. A plugin
|
|
3
|
+
* imports types only from here; at load, quanthea passes it the live kit (`ConnectorKit`).
|
|
4
|
+
*
|
|
5
|
+
* ```ts
|
|
6
|
+
* import type { ConnectorKit } from '@quanthea/plugin-kit';
|
|
7
|
+
* export const kitVersion = 0;
|
|
8
|
+
* export default function plugin(kit: ConnectorKit) {
|
|
9
|
+
* return [kit.defineConnector({ kind: 'example', … })];
|
|
10
|
+
* }
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
export type { ConnectorIcon, ConnectorInstance, ConnectorKind, OpenOptions, } from './connector-kind.js';
|
|
14
|
+
export type { ConnectorError, ConnectorErrorCode } from './errors.js';
|
|
15
|
+
export type { FrameBuilder, FrameBuilderOptions } from './frame-builder.js';
|
|
16
|
+
export type { Field, FieldType, Frame } from './frames.js';
|
|
17
|
+
export type { HttpClient, HttpClientOptions, HttpRequest, HttpResponse } from './http.js';
|
|
18
|
+
export { type ConnectorKit, type ConnectorPlugin, kitVersion } from './kit.js';
|
|
19
|
+
export type { BoundQuery, ExecutionContext, HttpField, HttpQuery, LogqlQuery, MongodbQuery, PromqlQuery, QueryLanguage, RedisQuery, SearchQuery, SqlDialect, SqlParameter, SqlPlaceholderStyle, SqlQuery, SqlRowLimit, TimeRange, } from './queries.js';
|
|
20
|
+
export type { FieldReference, HealthReport, SampleResult, SchemaEntity, SchemaField, SchemaSnapshot, } from './schema.js';
|
|
21
|
+
export type { SeriesData } from './series-frames.js';
|
package/index.js
ADDED
package/kit.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The kit quanthea hands a plugin when it loads it, and the shape of a plugin. The kit is the live
|
|
3
|
+
* one: its Zod, its error class and its helpers are the server's own, so a plugin's schemas and
|
|
4
|
+
* errors are the ones the core checks.
|
|
5
|
+
*/
|
|
6
|
+
import type { z } from 'zod';
|
|
7
|
+
import type { ConnectorKind, defineConnector } from './connector-kind.js';
|
|
8
|
+
import type { ConnectorError } from './errors.js';
|
|
9
|
+
import type { createFrameBuilder } from './frame-builder.js';
|
|
10
|
+
import type { createHttpClient } from './http.js';
|
|
11
|
+
import type { seriesFrames } from './series-frames.js';
|
|
12
|
+
/** The version of the kit this package describes. A plugin exports the version it was built for. */
|
|
13
|
+
export declare const kitVersion = 0;
|
|
14
|
+
/** What a plugin receives. */
|
|
15
|
+
export interface ConnectorKit {
|
|
16
|
+
/** The kit version, {@link kitVersion}. */
|
|
17
|
+
readonly version: typeof kitVersion;
|
|
18
|
+
/** The server's Zod: build the configuration and credential schemas with it. */
|
|
19
|
+
readonly z: typeof z;
|
|
20
|
+
/** Declares a connector kind, with the same checks as the built-in kinds. */
|
|
21
|
+
readonly defineConnector: typeof defineConnector;
|
|
22
|
+
/** The error a connector throws, with a code and a message safe to show. */
|
|
23
|
+
readonly ConnectorError: typeof ConnectorError;
|
|
24
|
+
/** Builds a frame row by row, with the row limit and truncation. */
|
|
25
|
+
readonly createFrameBuilder: typeof createFrameBuilder;
|
|
26
|
+
/** An HTTP client held to one origin, with a timeout and a size cap. */
|
|
27
|
+
readonly createHttpClient: typeof createHttpClient;
|
|
28
|
+
/** Turns results in the Prometheus API format into frames. */
|
|
29
|
+
readonly seriesFrames: typeof seriesFrames;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* A plugin's default export: given the kit, the connector kinds it adds.
|
|
33
|
+
*
|
|
34
|
+
* @param kit - The kit.
|
|
35
|
+
* @returns The kinds.
|
|
36
|
+
*/
|
|
37
|
+
export type ConnectorPlugin = (kit: ConnectorKit) => readonly ConnectorKind[];
|
package/languages.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** The query languages a connector kind can speak. The core binds each one; a plugin picks one. */
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
/** The query languages connectors speak. */
|
|
4
|
+
export declare const queryLanguages: readonly ["sql", "promql", "search", "logql", "http", "redis", "mongodb"];
|
|
5
|
+
/** Validates a query language. */
|
|
6
|
+
export declare const queryLanguageSchema: z.ZodEnum<{
|
|
7
|
+
sql: "sql";
|
|
8
|
+
promql: "promql";
|
|
9
|
+
search: "search";
|
|
10
|
+
logql: "logql";
|
|
11
|
+
http: "http";
|
|
12
|
+
redis: "redis";
|
|
13
|
+
mongodb: "mongodb";
|
|
14
|
+
}>;
|
|
15
|
+
/** A query language. */
|
|
16
|
+
export type QueryLanguage = z.infer<typeof queryLanguageSchema>;
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@quanthea/plugin-kit",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "The connector kit: the types a quanthea connector plugin is written against, a test kit and the conformance suite.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"quanthea",
|
|
7
|
+
"connector",
|
|
8
|
+
"plugin",
|
|
9
|
+
"kit"
|
|
10
|
+
],
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"author": "Josep Boix Requesens",
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/jboix/quanthea.git",
|
|
16
|
+
"directory": "packages/plugin-kit"
|
|
17
|
+
},
|
|
18
|
+
"homepage": "https://github.com/jboix/quanthea/tree/main/packages/plugin-kit#readme",
|
|
19
|
+
"bugs": {
|
|
20
|
+
"url": "https://github.com/jboix/quanthea/issues"
|
|
21
|
+
},
|
|
22
|
+
"type": "module",
|
|
23
|
+
"sideEffects": false,
|
|
24
|
+
"exports": {
|
|
25
|
+
".": {
|
|
26
|
+
"types": "./index.d.ts",
|
|
27
|
+
"default": "./index.js"
|
|
28
|
+
},
|
|
29
|
+
"./testing": {
|
|
30
|
+
"types": "./testing.d.ts",
|
|
31
|
+
"default": "./testing.js"
|
|
32
|
+
},
|
|
33
|
+
"./package.json": "./package.json"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"zod": "^4.6.5"
|
|
37
|
+
},
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public"
|
|
40
|
+
}
|
|
41
|
+
}
|