@tablecraft-app/plugin-api 0.0.0-stage → 1.2.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.
Files changed (93) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +46 -2
  3. package/dist/catalog.d.ts +112 -0
  4. package/dist/catalog.js +5 -0
  5. package/dist/completion.d.ts +109 -0
  6. package/dist/completion.js +12 -0
  7. package/dist/errors.d.ts +67 -0
  8. package/dist/errors.js +124 -0
  9. package/dist/explain.d.ts +58 -0
  10. package/dist/explain.js +1 -0
  11. package/dist/index.d.ts +16 -0
  12. package/dist/index.js +16 -0
  13. package/dist/inspection.d.ts +38 -0
  14. package/dist/inspection.js +21 -0
  15. package/dist/keyspace.d.ts +180 -0
  16. package/dist/keyspace.js +2 -0
  17. package/dist/manifest.d.ts +200 -0
  18. package/dist/manifest.js +238 -0
  19. package/dist/objects.d.ts +140 -0
  20. package/dist/objects.js +2 -0
  21. package/dist/plugin.d.ts +565 -0
  22. package/dist/plugin.js +58 -0
  23. package/dist/sessions.d.ts +59 -0
  24. package/dist/sessions.js +2 -0
  25. package/dist/sql/classify.d.ts +19 -0
  26. package/dist/sql/classify.js +95 -0
  27. package/dist/sql/complete.d.ts +23 -0
  28. package/dist/sql/complete.js +480 -0
  29. package/dist/sql/explain.d.ts +42 -0
  30. package/dist/sql/explain.js +108 -0
  31. package/dist/sql/format.d.ts +26 -0
  32. package/dist/sql/format.js +117 -0
  33. package/dist/sql/functions.d.ts +47 -0
  34. package/dist/sql/functions.js +159 -0
  35. package/dist/sql/generate.d.ts +22 -0
  36. package/dist/sql/generate.js +64 -0
  37. package/dist/sql/index.d.ts +16 -0
  38. package/dist/sql/index.js +16 -0
  39. package/dist/sql/inspect.d.ts +10 -0
  40. package/dist/sql/inspect.js +134 -0
  41. package/dist/sql/inspectContext.d.ts +78 -0
  42. package/dist/sql/inspectContext.js +251 -0
  43. package/dist/sql/inspectResolve.d.ts +6 -0
  44. package/dist/sql/inspectResolve.js +391 -0
  45. package/dist/sql/inspectStyle.d.ts +3 -0
  46. package/dist/sql/inspectStyle.js +384 -0
  47. package/dist/sql/inspectSyntax.d.ts +10 -0
  48. package/dist/sql/inspectSyntax.js +179 -0
  49. package/dist/sql/layout.d.ts +8 -0
  50. package/dist/sql/layout.js +114 -0
  51. package/dist/sql/layoutNodes.d.ts +46 -0
  52. package/dist/sql/layoutNodes.js +317 -0
  53. package/dist/sql/layoutPrint.d.ts +60 -0
  54. package/dist/sql/layoutPrint.js +806 -0
  55. package/dist/sql/layoutWriter.d.ts +21 -0
  56. package/dist/sql/layoutWriter.js +77 -0
  57. package/dist/sql/literals.d.ts +28 -0
  58. package/dist/sql/literals.js +78 -0
  59. package/dist/sql/namespace.d.ts +41 -0
  60. package/dist/sql/namespace.js +220 -0
  61. package/dist/sql/objects.d.ts +42 -0
  62. package/dist/sql/objects.js +222 -0
  63. package/dist/sql/parameters.d.ts +20 -0
  64. package/dist/sql/parameters.js +88 -0
  65. package/dist/sql/resolution.d.ts +73 -0
  66. package/dist/sql/resolution.js +192 -0
  67. package/dist/sql/routines.d.ts +27 -0
  68. package/dist/sql/routines.js +42 -0
  69. package/dist/sql/scope.d.ts +117 -0
  70. package/dist/sql/scope.js +540 -0
  71. package/dist/sql/select.d.ts +41 -0
  72. package/dist/sql/select.js +287 -0
  73. package/dist/sql/signature.d.ts +18 -0
  74. package/dist/sql/signature.js +137 -0
  75. package/dist/sql/splitter.d.ts +15 -0
  76. package/dist/sql/splitter.js +217 -0
  77. package/dist/sql/suggest.d.ts +6 -0
  78. package/dist/sql/suggest.js +36 -0
  79. package/dist/sql/tokens.d.ts +62 -0
  80. package/dist/sql/tokens.js +227 -0
  81. package/dist/sql/words.d.ts +23 -0
  82. package/dist/sql/words.js +72 -0
  83. package/dist/testing/index.d.ts +274 -0
  84. package/dist/testing/index.js +2398 -0
  85. package/dist/tls.d.ts +33 -0
  86. package/dist/tls.js +118 -0
  87. package/dist/url.d.ts +54 -0
  88. package/dist/url.js +228 -0
  89. package/dist/values.d.ts +44 -0
  90. package/dist/values.js +44 -0
  91. package/dist/version.d.ts +22 -0
  92. package/dist/version.js +29 -0
  93. package/package.json +42 -4
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 tranphucbol
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 CHANGED
@@ -1,3 +1,47 @@
1
- # Temporary Holding Version
1
+ # @tablecraft-app/plugin-api
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ The contract between [TableCraft](https://github.com/tranphucbol/table-craft) and its datasource
4
+ plugins: the types a plugin implements, the manifest schema, the shared SQL helpers and the
5
+ contract test suite every built-in plugin passes.
6
+
7
+ | Entry | Holds |
8
+ | :----------------------------------- | :-------------------------------------------------------------------------------------------------------- |
9
+ | `@tablecraft-app/plugin-api` | `DatasourcePlugin`, `Session`, `SqlLanguage`, the manifest schema, `PluginError`, `API_VERSION`, and more |
10
+ | `@tablecraft-app/plugin-api/sql` | The statement splitter, classifier, literal helpers, completer and formatter plugins build `language` on |
11
+ | `@tablecraft-app/plugin-api/testing` | `runPluginContract(plugin, fixture)`, the contract suite, for Vitest |
12
+
13
+ ## A plugin
14
+
15
+ A plugin is a folder with a `table-craft-plugin.json` manifest and an ES module whose default
16
+ export implements `DatasourcePlugin`. Put it in `plugins/<id>/` in the TableCraft profile folder.
17
+ Set the manifest's `apiVersion` to the version of this package you built against; bundle this
18
+ package and your driver into the module, since TableCraft loads the plugin from its folder alone.
19
+
20
+ ```ts
21
+ import type { DatasourcePlugin } from "@tablecraft-app/plugin-api";
22
+
23
+ const plugin: DatasourcePlugin = {
24
+ id: "example",
25
+ capabilities: ["sql"],
26
+ // connectionSchema, language and connect
27
+ };
28
+
29
+ export default plugin;
30
+ ```
31
+
32
+ Test it with the contract suite in a Vitest file: `runPluginContract(plugin, fixture)` connects
33
+ with `fixture.config` to a database seeded with the suite's `type_probe` table, and checks every
34
+ capability the manifest declares. `ContractFixture` documents each field.
35
+
36
+ ## Compatibility
37
+
38
+ This package follows semver, and its version is the plugin API version:
39
+
40
+ - TableCraft with plugin API `1.z` loads a plugin built for `1.y` when `y` is `z` or lower.
41
+ - A minor version only adds: new exports, new optional fields and methods, new capabilities.
42
+ - Breaking changes wait for the next major. Before removal, a member is marked `@deprecated` with
43
+ its replacement for at least one major.
44
+
45
+ ## License
46
+
47
+ MIT
@@ -0,0 +1,112 @@
1
+ /**
2
+ * A database or schema: the unit the explorer lists, introspects and caches (decision 022).
3
+ * `path` names it from the server down, such as `["table_craft", "public"]` on PostgreSQL.
4
+ */
5
+ export interface Namespace {
6
+ readonly path: readonly string[];
7
+ readonly name: string;
8
+ readonly kind: "database" | "schema";
9
+ /** The database's own catalog, such as `pg_catalog`; hidden unless the user asks. */
10
+ readonly system: boolean;
11
+ /** Where unqualified names resolve for this connection. */
12
+ readonly current: boolean;
13
+ }
14
+ export interface ColumnMeta {
15
+ readonly name: string;
16
+ /** 1-based, in table order. */
17
+ readonly position: number;
18
+ /** The type as the database spells it, such as `numeric(12,2)`. */
19
+ readonly type: string;
20
+ readonly nullable: boolean;
21
+ /** The default expression as the database prints it; null when there is none. */
22
+ readonly default: string | null;
23
+ readonly comment: string | null;
24
+ readonly autoIncrement: boolean;
25
+ }
26
+ export interface Key {
27
+ readonly name: string;
28
+ readonly columns: readonly string[];
29
+ }
30
+ export interface ForeignKey {
31
+ readonly name: string;
32
+ readonly columns: readonly string[];
33
+ readonly target: {
34
+ readonly path: readonly string[];
35
+ readonly relation: string;
36
+ readonly columns: readonly string[];
37
+ };
38
+ /** The referential action as SQL spells it, such as `CASCADE` or `NO ACTION`. */
39
+ readonly onDelete: string;
40
+ readonly onUpdate: string;
41
+ }
42
+ export interface Index {
43
+ readonly name: string;
44
+ readonly columns: readonly string[];
45
+ readonly unique: boolean;
46
+ readonly primary: boolean;
47
+ }
48
+ export type RelationKind = "table" | "view" | "materializedView";
49
+ export interface Relation {
50
+ readonly name: string;
51
+ readonly kind: RelationKind;
52
+ readonly comment: string | null;
53
+ /** Ordered by position. */
54
+ readonly columns: readonly ColumnMeta[];
55
+ readonly primaryKey: Key | null;
56
+ readonly uniqueKeys: readonly Key[];
57
+ readonly foreignKeys: readonly ForeignKey[];
58
+ readonly indexes: readonly Index[];
59
+ }
60
+ export declare const ROUTINE_PARAMETER_MODES: readonly ["in", "out", "inout", "variadic"];
61
+ export type RoutineParameterMode = (typeof ROUTINE_PARAMETER_MODES)[number];
62
+ export interface RoutineParameter {
63
+ /** Null when the database records none, as PostgreSQL allows. */
64
+ readonly name: string | null;
65
+ /** As the database prints it, `numeric` or `decimal(12,2)`. */
66
+ readonly type: string;
67
+ readonly mode: RoutineParameterMode;
68
+ readonly hasDefault: boolean;
69
+ }
70
+ /** Name, kind and signature are unique in a namespace; PostgreSQL overloads are separate routines. */
71
+ export interface Routine {
72
+ readonly name: string;
73
+ readonly kind: "function" | "procedure";
74
+ /** The argument list as the database prints it, without parentheses. */
75
+ readonly signature: string;
76
+ /** In declaration order; a function's result and `RETURNS TABLE` columns are not parameters. */
77
+ readonly parameters: readonly RoutineParameter[];
78
+ /** A function's result as the database prints it; null for a procedure. */
79
+ readonly returns: string | null;
80
+ }
81
+ export interface Sequence {
82
+ readonly name: string;
83
+ }
84
+ /** Everything one `describe` returns; every list but `columns` is sorted by name. */
85
+ export interface NamespaceCatalog {
86
+ readonly path: readonly string[];
87
+ readonly relations: readonly Relation[];
88
+ readonly routines: readonly Routine[];
89
+ readonly sequences: readonly Sequence[];
90
+ }
91
+ /** Present on a session exactly when the plugin declares `schemaTree`. */
92
+ export interface Introspector {
93
+ /** Every namespace the connection can see, system ones included and marked. */
94
+ namespaces(): Promise<readonly Namespace[]>;
95
+ /**
96
+ * Rejects with a `PluginError` coded `introspectionFailed` when the namespace does not exist
97
+ * or the user cannot read it.
98
+ */
99
+ describe(path: readonly string[]): Promise<NamespaceCatalog>;
100
+ /** `name` inside `path`, quoted the way this database quotes identifiers. */
101
+ qualifiedName(path: readonly string[], name: string): string;
102
+ /**
103
+ * Present exactly when the plugin declares `ddl` (decision 029). The statements that create
104
+ * relation `name` in `path`, read from the database on every call: each ends in `;` and a blank
105
+ * line separates them. Rejects with `DefinitionNotFoundError` when there is no such relation.
106
+ */
107
+ definition?(path: readonly string[], name: string): Promise<string>;
108
+ }
109
+ /** Sorts by `name`, the order every catalog list but columns is returned in. */
110
+ export declare function byName<T extends {
111
+ readonly name: string;
112
+ }>(items: Iterable<T>): T[];
@@ -0,0 +1,5 @@
1
+ export const ROUTINE_PARAMETER_MODES = ["in", "out", "inout", "variadic"];
2
+ /** Sorts by `name`, the order every catalog list but columns is returned in. */
3
+ export function byName(items) {
4
+ return [...items].sort((left, right) => (left.name < right.name ? -1 : left.name > right.name ? 1 : 0));
5
+ }
@@ -0,0 +1,109 @@
1
+ import type { ForeignKey, Namespace, Relation } from "./catalog.js";
2
+ /** What a completion item names; the console draws each with the Database pane's glyph for it. */
3
+ export declare const COMPLETION_KINDS: readonly ["namespace", "table", "view", "column", "alias", "cte", "join", "function", "keyword"];
4
+ export type CompletionKind = (typeof COMPLETION_KINDS)[number];
5
+ export interface CompletionItem {
6
+ /** What the popup shows and the editor filters on. */
7
+ readonly label: string;
8
+ readonly kind: CompletionKind;
9
+ /** A column's type, a relation's namespace or a join's foreign key; null when there is nothing to add. */
10
+ readonly detail: string | null;
11
+ /** The text accepting the item inserts over the result's `from`…`to`, quoted where the dialect needs it. */
12
+ readonly apply: string;
13
+ /** Orders items the typed prefix matches equally well; higher comes first, within -99…99. */
14
+ readonly boost: number;
15
+ /** Longer text the popup shows beside the selected item, such as a function's signatures and summary. */
16
+ readonly info: string | null;
17
+ /** Where the caret lands, as an offset into `apply`; null for its end. */
18
+ readonly caret: number | null;
19
+ }
20
+ export interface FunctionParameter {
21
+ readonly name: string;
22
+ readonly optional?: boolean;
23
+ /** Repeats: the call may pass it any number of times. */
24
+ readonly variadic?: boolean;
25
+ }
26
+ /** One way to call a function: its parameters in order and what it returns. */
27
+ export interface FunctionSignature {
28
+ readonly parameters: readonly FunctionParameter[];
29
+ readonly returns: string;
30
+ }
31
+ /** The function call around the caret (decision 098). */
32
+ export interface SignatureHelp {
33
+ readonly name: string;
34
+ readonly summary: string;
35
+ readonly signatures: readonly FunctionSignature[];
36
+ /** The zero-based argument the caret is in: the top-level commas before it inside the call. */
37
+ readonly argument: number;
38
+ /** The call's name to the end of its arguments, or to the caret while it is still open. */
39
+ readonly from: number;
40
+ readonly to: number;
41
+ }
42
+ /** What completion knows about the server it completes for; null fields when the catalog could not open. */
43
+ export interface CompletionServer {
44
+ /** The version string the session reports, such as `8.4.3` or `5.7.25-TiDB-v4.0.14`. */
45
+ readonly version: string | null;
46
+ }
47
+ /** The table a clause body is written against, such as the table editor's WHERE bar (plan 009 decision 9). */
48
+ export interface CompletionScope {
49
+ readonly path: readonly string[];
50
+ readonly relation: string;
51
+ }
52
+ export interface CompletionRequest {
53
+ readonly text: string;
54
+ /** The caret, in UTF-16 offsets into `text` (decision 023). */
55
+ readonly offset: number;
56
+ /** When present, `text` is a clause body with `relation` in scope, not a whole script. */
57
+ readonly scope?: CompletionScope;
58
+ }
59
+ export interface CompletionResult {
60
+ /** The span accepting an item replaces: the word typed before the caret. */
61
+ readonly from: number;
62
+ readonly to: number;
63
+ readonly items: readonly CompletionItem[];
64
+ /**
65
+ * A regular expression source the editor may keep filtering these items with while the typed word
66
+ * still matches it, without asking again; null to ask again on every keystroke.
67
+ */
68
+ readonly validFor: string | null;
69
+ }
70
+ export interface ResolveRequest {
71
+ readonly text: string;
72
+ readonly offset: number;
73
+ }
74
+ /** Where the name at the caret was declared (plan 009 decision 10). */
75
+ export type Declaration = {
76
+ readonly kind: "alias" | "cte";
77
+ readonly from: number;
78
+ readonly to: number;
79
+ } | {
80
+ readonly kind: "relation";
81
+ readonly path: readonly string[];
82
+ readonly relation: string;
83
+ } | {
84
+ readonly kind: "column";
85
+ readonly path: readonly string[];
86
+ readonly relation: string;
87
+ readonly column: string;
88
+ };
89
+ /** A foreign key in `path`.`relation` that targets the relation asked about. */
90
+ export interface IncomingForeignKey {
91
+ readonly path: readonly string[];
92
+ readonly relation: string;
93
+ readonly foreignKey: ForeignKey;
94
+ }
95
+ /**
96
+ * What completion may read about the datasource (decision 028): the engine's catalog cache. It
97
+ * never touches a console's session, and answers with what it has once a describe runs too long.
98
+ */
99
+ export interface CompletionCatalog {
100
+ /** Where unqualified names resolve; null when the datasource reports no current namespace. */
101
+ readonly current: readonly string[] | null;
102
+ /** The server behind the cache, so a plugin offers only the functions it has (decision 097). */
103
+ readonly server: CompletionServer;
104
+ namespaces(): Promise<readonly Namespace[]>;
105
+ /** Every relation in `path`, described on demand; empty when the describe fails or runs too long. */
106
+ relations(path: readonly string[]): Promise<readonly Relation[]>;
107
+ /** Foreign keys targeting `path`.`relation` in every namespace described so far. */
108
+ referencing(path: readonly string[], relation: string): Promise<readonly IncomingForeignKey[]>;
109
+ }
@@ -0,0 +1,12 @@
1
+ /** What a completion item names; the console draws each with the Database pane's glyph for it. */
2
+ export const COMPLETION_KINDS = [
3
+ "namespace",
4
+ "table",
5
+ "view",
6
+ "column",
7
+ "alias",
8
+ "cte",
9
+ "join",
10
+ "function",
11
+ "keyword",
12
+ ];
@@ -0,0 +1,67 @@
1
+ /** Failures the host tells apart; anything else a plugin throws is reported as `statementFailed`. */
2
+ export declare const PLUGIN_ERROR_CODES: readonly ["cancelled", "connectionFailed", "statementFailed", "introspectionFailed", "definitionNotFound", "explainUnsupported", "connectionLost", "sessionBusy", "conflict"];
3
+ export type PluginErrorCode = (typeof PLUGIN_ERROR_CODES)[number];
4
+ /**
5
+ * Where the database located a failure, relative to the statement text the plugin received:
6
+ * `offset` is 0-based in UTF-16 code units (a JavaScript string index); `line` and `column` count
7
+ * from 1, the column in UTF-16 code units too.
8
+ */
9
+ export type ErrorPosition = {
10
+ readonly offset: number;
11
+ } | {
12
+ readonly line: number;
13
+ readonly column: number;
14
+ };
15
+ export interface PluginErrorOptions extends ErrorOptions {
16
+ /** Leave it out when the database did not say; the host then underlines nothing. */
17
+ readonly position?: ErrorPosition;
18
+ }
19
+ /** What a plugin throws when the host should react to the kind of failure, not just show it. */
20
+ export declare class PluginError extends Error {
21
+ readonly code: PluginErrorCode;
22
+ readonly name = "PluginError";
23
+ readonly position: ErrorPosition | undefined;
24
+ constructor(code: PluginErrorCode, message: string, options?: PluginErrorOptions);
25
+ }
26
+ /**
27
+ * Structural, because every bundled plugin carries its own copy of this module, so `instanceof`
28
+ * fails for an error thrown by a plugin and caught by the host.
29
+ */
30
+ export declare function isPluginError(error: unknown): error is PluginError;
31
+ /**
32
+ * The position a plugin attached to a `PluginError`, checked by shape, since the error comes from
33
+ * another bundle; anything malformed reads as no position.
34
+ */
35
+ export declare function errorPositionOf(error: unknown): ErrorPosition | undefined;
36
+ /** `position` as a 0-based offset into `text`, clamped to the text. */
37
+ export declare function offsetOfPosition(text: string, position: ErrorPosition): number;
38
+ /**
39
+ * A `connectionFailed` the SSL settings caused: a certificate file that cannot be read or used, or
40
+ * a server certificate that failed verification. The host then points at those settings instead
41
+ * of the host, port, user and password (decision 072).
42
+ */
43
+ export declare class TlsSettingsError extends PluginError {
44
+ readonly tlsSettings = true;
45
+ constructor(message: string, options?: ErrorOptions);
46
+ }
47
+ /** Structural for the same reason as `isPluginError`. */
48
+ export declare function isTlsSettingsError(error: unknown): error is TlsSettingsError;
49
+ /**
50
+ * A guarded `Keyspace.apply` found `target` changed since it was read (decision 115): `detail`
51
+ * says what differs, such as `field name is now "Bo"`. Nothing was written.
52
+ */
53
+ export declare class ConflictError extends PluginError {
54
+ readonly target: string;
55
+ readonly detail: string;
56
+ constructor(target: string, detail: string, options?: ErrorOptions);
57
+ }
58
+ /**
59
+ * `Introspector.definition` asked for a relation the database does not have, usually one dropped
60
+ * or renamed since the catalog was read (decision 029). Coded `definitionNotFound`, so the host
61
+ * recognises it with `isPluginError` across plugin bundles.
62
+ */
63
+ export declare class DefinitionNotFoundError extends PluginError {
64
+ readonly path: readonly string[];
65
+ readonly relation: string;
66
+ constructor(path: readonly string[], relation: string, options?: ErrorOptions);
67
+ }
package/dist/errors.js ADDED
@@ -0,0 +1,124 @@
1
+ /** Failures the host tells apart; anything else a plugin throws is reported as `statementFailed`. */
2
+ export const PLUGIN_ERROR_CODES = [
3
+ "cancelled",
4
+ "connectionFailed",
5
+ "statementFailed",
6
+ "introspectionFailed",
7
+ "definitionNotFound",
8
+ /** `Session.explain` refused the statement; the message says why and what to explain instead. */
9
+ "explainUnsupported",
10
+ /**
11
+ * The connection was gone before the statement was sent, so the host may reconnect and run it
12
+ * again; `Session.ping` rejects with it too.
13
+ */
14
+ "connectionLost",
15
+ /**
16
+ * The session is still busy with an earlier statement or result and refused this one unsent
17
+ * (decision 058). The host waits for every close first, so this is a bug it logs and heals by
18
+ * reconnecting; never a message for the user.
19
+ */
20
+ "sessionBusy",
21
+ /**
22
+ * A guarded write found what it was to change already changed by someone else, and wrote
23
+ * nothing (decision 115); the host offers to reload or to overwrite.
24
+ */
25
+ "conflict",
26
+ ];
27
+ /** What a plugin throws when the host should react to the kind of failure, not just show it. */
28
+ export class PluginError extends Error {
29
+ code;
30
+ name = "PluginError";
31
+ position;
32
+ constructor(code, message, options) {
33
+ super(message, options);
34
+ this.code = code;
35
+ this.position = options?.position;
36
+ }
37
+ }
38
+ /**
39
+ * Structural, because every bundled plugin carries its own copy of this module, so `instanceof`
40
+ * fails for an error thrown by a plugin and caught by the host.
41
+ */
42
+ export function isPluginError(error) {
43
+ if (!(error instanceof Error) || error.name !== "PluginError")
44
+ return false;
45
+ const code = error.code;
46
+ return PLUGIN_ERROR_CODES.some((known) => known === code);
47
+ }
48
+ function isWholeAtLeast(value, least) {
49
+ return typeof value === "number" && Number.isInteger(value) && value >= least;
50
+ }
51
+ /**
52
+ * The position a plugin attached to a `PluginError`, checked by shape, since the error comes from
53
+ * another bundle; anything malformed reads as no position.
54
+ */
55
+ export function errorPositionOf(error) {
56
+ if (!isPluginError(error))
57
+ return undefined;
58
+ const position = error.position;
59
+ if (typeof position !== "object" || position === null)
60
+ return undefined;
61
+ const { offset, line, column } = position;
62
+ if (isWholeAtLeast(offset, 0))
63
+ return { offset };
64
+ if (isWholeAtLeast(line, 1) && isWholeAtLeast(column, 1))
65
+ return { line, column };
66
+ return undefined;
67
+ }
68
+ /** `position` as a 0-based offset into `text`, clamped to the text. */
69
+ export function offsetOfPosition(text, position) {
70
+ if ("offset" in position)
71
+ return Math.min(position.offset, text.length);
72
+ let start = 0;
73
+ for (let line = 1; line < position.line; line += 1) {
74
+ const end = text.indexOf("\n", start);
75
+ if (end === -1)
76
+ return text.length;
77
+ start = end + 1;
78
+ }
79
+ const lineEnd = text.indexOf("\n", start);
80
+ const limit = lineEnd === -1 ? text.length : lineEnd;
81
+ return Math.min(start + position.column - 1, limit);
82
+ }
83
+ /**
84
+ * A `connectionFailed` the SSL settings caused: a certificate file that cannot be read or used, or
85
+ * a server certificate that failed verification. The host then points at those settings instead
86
+ * of the host, port, user and password (decision 072).
87
+ */
88
+ export class TlsSettingsError extends PluginError {
89
+ tlsSettings = true;
90
+ constructor(message, options) {
91
+ super("connectionFailed", message, options);
92
+ }
93
+ }
94
+ /** Structural for the same reason as `isPluginError`. */
95
+ export function isTlsSettingsError(error) {
96
+ return isPluginError(error) && error.tlsSettings === true;
97
+ }
98
+ /**
99
+ * A guarded `Keyspace.apply` found `target` changed since it was read (decision 115): `detail`
100
+ * says what differs, such as `field name is now "Bo"`. Nothing was written.
101
+ */
102
+ export class ConflictError extends PluginError {
103
+ target;
104
+ detail;
105
+ constructor(target, detail, options) {
106
+ super("conflict", `${target} changed since it was read: ${detail}. Reload it, or overwrite the change.`, options);
107
+ this.target = target;
108
+ this.detail = detail;
109
+ }
110
+ }
111
+ /**
112
+ * `Introspector.definition` asked for a relation the database does not have, usually one dropped
113
+ * or renamed since the catalog was read (decision 029). Coded `definitionNotFound`, so the host
114
+ * recognises it with `isPluginError` across plugin bundles.
115
+ */
116
+ export class DefinitionNotFoundError extends PluginError {
117
+ path;
118
+ relation;
119
+ constructor(path, relation, options) {
120
+ super("definitionNotFound", `There is no relation ${relation} in ${path.join(".")}; synchronize the data source to see what it holds now.`, options);
121
+ this.path = path;
122
+ this.relation = relation;
123
+ }
124
+ }
@@ -0,0 +1,58 @@
1
+ import type { ServerMessage } from "./plugin.js";
2
+ /** A name and its value as the database printed it, such as `Filter` and `(total > 10)`. */
3
+ export interface PlanProperty {
4
+ readonly name: string;
5
+ readonly value: string;
6
+ }
7
+ /**
8
+ * One step of a plan (decision 031), normalised from whatever the dialect prints. Numbers are plain
9
+ * JavaScript numbers, not wire values: they are estimates and timings, never data. Null where the
10
+ * dialect reports nothing, so a view leaves the cell empty.
11
+ */
12
+ export interface PlanNode {
13
+ /** What the step does, such as `Seq Scan` or `Nested loop inner join`. */
14
+ readonly operation: string;
15
+ /** The relation it reads, such as `orders o`; null when it reads none or the dialect does not say. */
16
+ readonly target: string | null;
17
+ /** One line more about the step, such as the index it uses; null when there is none. */
18
+ readonly detail: string | null;
19
+ readonly estimatedRows: number | null;
20
+ /** The planner's total cost, in the dialect's own units. */
21
+ readonly estimatedCost: number | null;
22
+ readonly actualRows: number | null;
23
+ /** Milliseconds until the step returned its last row, per loop. */
24
+ readonly actualTimeMs: number | null;
25
+ readonly loops: number | null;
26
+ /** Everything else the dialect reports about the step, in its order. */
27
+ readonly properties: readonly PlanProperty[];
28
+ readonly children: readonly PlanNode[];
29
+ }
30
+ /** What `Session.explain` answers. */
31
+ export interface ExplainedPlan {
32
+ /** The EXPLAIN statement the plugin sent, which is what history records. */
33
+ readonly statement: string;
34
+ /** Whether the statement ran (Explain Analyse) rather than only being planned. */
35
+ readonly analyzed: boolean;
36
+ readonly roots: readonly PlanNode[];
37
+ /** Facts about the whole plan, such as `Planning Time` and `Execution Time`. */
38
+ readonly summary: readonly PlanProperty[];
39
+ /** The plan as the database printed it. */
40
+ readonly raw: string;
41
+ /** What the server said while explaining, as `ExecuteResult.messages`; present exactly when the plugin declares `serverMessages`. */
42
+ readonly messages?: readonly ServerMessage[];
43
+ }
44
+ export interface ExplainOptions {
45
+ /** Run the statement and report what it did (Explain Analyse), not only how it would run. */
46
+ readonly analyze: boolean;
47
+ }
48
+ /**
49
+ * Whether a statement can be explained, decided without a database. `writes` says the statement
50
+ * changes something, so analysing it, which runs it, needs the user's consent first.
51
+ */
52
+ export type Explainability = {
53
+ readonly ok: true;
54
+ readonly writes: boolean;
55
+ } | {
56
+ readonly ok: false;
57
+ readonly reason: string;
58
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,16 @@
1
+ export { byName, type ColumnMeta, type ForeignKey, type Index, type Introspector, type Key, type Namespace, type NamespaceCatalog, type Relation, type RelationKind, ROUTINE_PARAMETER_MODES, type Routine, type RoutineParameter, type RoutineParameterMode, type Sequence, } from "./catalog.js";
2
+ export { COMPLETION_KINDS, type CompletionCatalog, type CompletionItem, type CompletionKind, type CompletionRequest, type CompletionResult, type CompletionScope, type CompletionServer, type Declaration, type FunctionParameter, type FunctionSignature, type IncomingForeignKey, type ResolveRequest, type SignatureHelp, } from "./completion.js";
3
+ export { INSPECTION_IDS, type InspectionId, type InspectionRequest, type Problem, PROBLEM_SEVERITIES, type ProblemSeverity, type QuickFix, type TextEdit, } from "./inspection.js";
4
+ export { ConflictError, DefinitionNotFoundError, type ErrorPosition, errorPositionOf, isPluginError, isTlsSettingsError, offsetOfPosition, PLUGIN_ERROR_CODES, PluginError, type PluginErrorCode, type PluginErrorOptions, TlsSettingsError, } from "./errors.js";
5
+ export { type ExplainedPlan, type Explainability, type ExplainOptions, type PlanNode, type PlanProperty, } from "./explain.js";
6
+ export { KEY_TYPES, type KeyApplied, type KeyApplyOptions, type KeyBytes, type KeyChange, type KeyContents, type KeyDatabase, type KeyDetails, type KeyExpiry, type KeyInfo, type KeyName, type KeyReadRequest, type KeyScan, type KeyScanRequest, type Keyspace, type KeyType, } from "./keyspace.js";
7
+ export { OBJECT_KINDS, type CatalogObject, type CheckDesign, type ColumnDesign, type DdlContext, type DdlScript, type ForeignKeyDesign, type IndexDesign, type ObjectChange, type ObjectChangeKind, type ObjectEditor, type ObjectFeatures, type ObjectKind, type TableDesign, } from "./objects.js";
8
+ export { CONNECTION_FIELD_GROUPS, CONNECTION_FIELD_KINDS, CONNECTION_URL_FORMS, CONNECTION_URL_PARTS, connectionFieldSchema, connectionUrlSchema, MANIFEST_FILE, networkSpecSchema, pluginManifestSchema, TLS_FIELD_ROLES, tlsSpecSchema, type ConnectionField, type ConnectionFieldGroup, type ConnectionFieldKind, type ConnectionUrl, type ConnectionUrlForm, type ConnectionUrlPart, type NetworkSpec, type PluginManifest, type TlsFieldRole, type TlsSpec, } from "./manifest.js";
9
+ export { ConnectionUrlError, formatConnectionUrl, parseConnectionUrl, type ConnectionForm, type ConnectionUrlSpec, type ConnectionValue, type ParsedConnectionUrl, } from "./url.js";
10
+ export { type BoundStatement, CAPABILITIES, type Capability, type Column, type ColumnOrigin, type CommandLanguage, type CommandReply, type ConnectOptions, type DatasourcePlugin, type ExecuteOptions, type ExecuteResult, type FormatOptions, FORMAT_STYLES, type FormatStyle, GENERATED_STATEMENTS, type GeneratedStatement, IMPORT_KINDS, type ImportKind, type InferredColumn, type InsertRow, type InsertTarget, KEYWORD_CASES, type NamespaceSwitch, NODE_ALL_PRIMARIES, NODE_AUTO, NODE_ROLES, type NodeRole, type ServerInfo, type ServerInfoSection, type ServerNode, type SlowCommand, switchableTo, type NewColumn, type KeywordCase, PARAMETER_STYLES, type ParameterStyle, type ParameterValue, type RoutineArgument, type RoutineCall, type Row, type SavepointStatements, type SelectSource, omittedMessages, SERVER_MESSAGE_LEVELS, SERVER_MESSAGE_LIMIT, type ServerMessage, type ServerMessageLevel, type SqlParameter, type Session, type SqlLanguage, STATEMENT_KINDS, type StatementClass, type StatementKind, type StatementSpan, type StatementStream, type StreamedStatement, type TlsInfo, TRANSACTION_MODES, type TransactionMode, type Transactions, } from "./plugin.js";
11
+ export { SERVER_SESSION_STATES, type ServerSession, type ServerSessionState, type SessionListing, type SessionMonitor, type SessionTarget, } from "./sessions.js";
12
+ export { TLS_CHAIN_CODES, TLS_HOST_CODE, homeExpanded, tlsFailureMessage, tlsFileMessage, tlsKeyIsEncrypted, tlsKeyMessage, type TlsVerification, } from "./tls.js";
13
+ export { BYTES_PREVIEW_LENGTH, toBytesValue, toWireInteger, toWireValue, type WireValueOptions, type BigIntValue, type BytesValue, type DateValue, type JsonValue, type TypeClass, type WireValue, } from "./values.js";
14
+ export { API_VERSION, incompatibility, type Incompatibility, isCompatible, parseVersion } from "./version.js";
15
+ /** Plugins build `connectionSchema` with the zod the contract was compiled against, not their own pick. */
16
+ export { z } from "zod";
package/dist/index.js ADDED
@@ -0,0 +1,16 @@
1
+ export { byName, ROUTINE_PARAMETER_MODES, } from "./catalog.js";
2
+ export { COMPLETION_KINDS, } from "./completion.js";
3
+ export { INSPECTION_IDS, PROBLEM_SEVERITIES, } from "./inspection.js";
4
+ export { ConflictError, DefinitionNotFoundError, errorPositionOf, isPluginError, isTlsSettingsError, offsetOfPosition, PLUGIN_ERROR_CODES, PluginError, TlsSettingsError, } from "./errors.js";
5
+ export {} from "./explain.js";
6
+ export { KEY_TYPES, } from "./keyspace.js";
7
+ export { OBJECT_KINDS, } from "./objects.js";
8
+ export { CONNECTION_FIELD_GROUPS, CONNECTION_FIELD_KINDS, CONNECTION_URL_FORMS, CONNECTION_URL_PARTS, connectionFieldSchema, connectionUrlSchema, MANIFEST_FILE, networkSpecSchema, pluginManifestSchema, TLS_FIELD_ROLES, tlsSpecSchema, } from "./manifest.js";
9
+ export { ConnectionUrlError, formatConnectionUrl, parseConnectionUrl, } from "./url.js";
10
+ export { CAPABILITIES, FORMAT_STYLES, GENERATED_STATEMENTS, IMPORT_KINDS, KEYWORD_CASES, NODE_ALL_PRIMARIES, NODE_AUTO, NODE_ROLES, switchableTo, PARAMETER_STYLES, omittedMessages, SERVER_MESSAGE_LEVELS, SERVER_MESSAGE_LIMIT, STATEMENT_KINDS, TRANSACTION_MODES, } from "./plugin.js";
11
+ export { SERVER_SESSION_STATES, } from "./sessions.js";
12
+ export { TLS_CHAIN_CODES, TLS_HOST_CODE, homeExpanded, tlsFailureMessage, tlsFileMessage, tlsKeyIsEncrypted, tlsKeyMessage, } from "./tls.js";
13
+ export { BYTES_PREVIEW_LENGTH, toBytesValue, toWireInteger, toWireValue, } from "./values.js";
14
+ export { API_VERSION, incompatibility, isCompatible, parseVersion } from "./version.js";
15
+ /** Plugins build `connectionSchema` with the zod the contract was compiled against, not their own pick. */
16
+ export { z } from "zod";
@@ -0,0 +1,38 @@
1
+ /** How loudly the console marks a problem (plan 108): red wavy, amber wavy, or muted dotted. */
2
+ export declare const PROBLEM_SEVERITIES: readonly ["error", "warning", "weak"];
3
+ export type ProblemSeverity = (typeof PROBLEM_SEVERITIES)[number];
4
+ /**
5
+ * The inspections `sqlInspector` runs. The ids are DataGrip's, so a `-- noinspection <Id>` comment
6
+ * written there silences the same check here.
7
+ */
8
+ export declare const INSPECTION_IDS: readonly ["SqlSyntax", "SqlResolve", "SqlAmbiguousColumn", "SqlReservedWordAsName", "SqlInsertValues", "SqlWithoutWhere", "SqlNullComparison", "SqlConstantCondition", "SqlUnusedCte", "SqlDuplicateAlias", "SqlRedundantOrderingDirection", "SqlRedundantAlias", "SqlRedundantElseNull"];
9
+ export type InspectionId = (typeof INSPECTION_IDS)[number];
10
+ /** One replacement in the inspected text; offsets are UTF-16 indexes into `InspectionRequest.text`. */
11
+ export interface TextEdit {
12
+ readonly from: number;
13
+ readonly to: number;
14
+ readonly insert: string;
15
+ }
16
+ /** A fix the user can apply from Alt+Enter: its edits apply together, as one undo step. */
17
+ export interface QuickFix {
18
+ readonly title: string;
19
+ readonly edits: readonly TextEdit[];
20
+ /** Where the caret goes after the edits, as an offset into the edited text; absent leaves it. */
21
+ readonly caret?: number;
22
+ }
23
+ /** A problem found while typing, before anything runs. */
24
+ export interface Problem {
25
+ readonly from: number;
26
+ readonly to: number;
27
+ readonly severity: ProblemSeverity;
28
+ /** An `INSPECTION_IDS` entry, or a plugin's own id for a check it adds. */
29
+ readonly inspection: string;
30
+ readonly message: string;
31
+ readonly fixes: readonly QuickFix[];
32
+ }
33
+ export interface InspectionRequest {
34
+ /** The whole console text; problems cover every statement in it. */
35
+ readonly text: string;
36
+ /** Inspections the user turned off; the plugin skips them. */
37
+ readonly disabled?: readonly string[];
38
+ }