1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
// Copyright (C) 2026 Gabriel Shea
// Licensed under either of the Apache License, Version 2.0 or the MIT
// license, at your option.
//! # razeri-plugin-api
//!
//! Extension point traits and registries for the Razeri platform.
//!
//! This crate defines the **plugin API surface** — the traits that third-party
//! developers implement to extend Razeri with new database dialects, storage
//! backends, LLM providers, language renderers, and event sinks.
//!
//! ## Extension Points
//!
//! | Trait | Registry | Key Type |
//! |-------|----------|----------|
//! | [`PlatformDialect`] | [`PlatformRegistry`] | string (canonical name) |
//! | [`StorageProviderFactory`] | [`StorageRegistry`] | `StoragePlatform` enum + string |
//! | [`LlmClientFactory`] / [`LlmClient`] | [`LlmRegistry`] | string |
//! | [`LlmModelAdapter`] | [`ModelRegistry`] | (provider, model) pair |
//! | [`LanguageRendererFactory`] | [`LanguageRegistry`] | string |
//! | [`EventSink`] | [`EventRegistry`] | fan-out (all sinks) |
//!
//! ## Beside the extension points
//!
//! | Module | What it holds |
//! |--------|---------------|
//! | [`conformance`] | the report that grades a dialect against everything it owes, run from the dialect's own tests |
//! | [`resolve`] | a platform name, an alias or `name@version`, turned into the dialect that renders it |
//! | [`process`] | the one dialect registry a process resolves names against, and the plugin directory that feeds it |
//! | [`dynamic`] | loading a plugin built as a shared library, and refusing one built differently from the razeri that loads it |
//! | [`alerting`] | alert rules and health summaries evaluated over the event stream |
//! | [`sinks`] | the event sinks razeri ships, written against the same [`EventSink`] trait a plugin implements |
//!
//! ## Composition Root
//!
//! Use [`PluginRegistryBuilder`] to wire everything together at application
//! startup, then pass the resulting [`PluginRegistry`] to subsystems. The
//! builder's own page shows it in use.
// ── Convenience re-exports ────────────────────────────────────────────
pub use PluginRegistryBuilder;
pub use ;
pub use ;
// The contract a plugin's types and traits are written against, re-exported so
// a dialect crate can depend on this one crate and reach everything it needs.
pub use ;
pub use razeri_plugin_contract;
/// **The named routine grammars, spelled.**
///
/// A dialect whose engine has a routine in a grammar Razeri does not carry
/// renders the whole `CREATE` itself. These three functions write out the
/// grammars Razeri does carry, from the same
/// [`RoutineSpec`](razeri_plugin_contract::RoutineSpec) a dialect receives, so a
/// grammar that is *"PL/pgSQL with one tweak"* starts from PL/pgSQL and says
/// what differs rather than being written from nothing.
pub use routine_render;
pub use ;
pub use load_plugins_from_dir;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use PluginRegistry;
pub use ResolveError;
pub use ;
// Re-export built-in sink types and factory. The JSONL sink is native-only
// (filesystem via `tokio::fs`), so its re-export is absent on wasm.
pub use JsonlSink;
pub use StdoutSink;
pub use WebhookSink;
pub use ;
// Re-export alerting and health model
pub use ;
// Re-export inventory registration types
pub use ;
/// **Make a crate a razeri plugin, in one line.**
///
/// Name a function that registers what the crate provides:
///
/// ```ignore
/// use razeri_plugin_api::PluginRegistryBuilder;
/// use std::sync::Arc;
///
/// fn register(builder: &mut PluginRegistryBuilder) {
/// builder.register_dialect(Arc::new(MyDb));
/// }
///
/// razeri_plugin_api::export_plugin!(register);
/// ```
///
/// The crate can then reach razeri two ways, and the same line serves both:
///
/// - **Loaded from a plugin directory**, built as a `cdylib`. The line exports
/// how the library was built and the function razeri calls to register it.
/// Razeri reads the first before it calls the second, and refuses a library
/// built with another compiler or against other plugin crates.
/// - **Linked into a razeri you build**, as an ordinary dependency. The line
/// records `register` so the registry finds it at start-up, the same way it
/// finds razeri's own dialects.
///
/// Use it once per crate, at the top level of `lib.rs`.
// ── Convenience helpers ───────────────────────────────────────────────
use Arc;
/// Resolve a platform name to the dialect that renders it.
///
/// This is the **one resolver** — all service crates call it instead of
/// matching on names themselves. Each dialect declares the spellings it answers
/// to, so `"pg"` reaches `PostgreSQL` and `"mssql"` reaches SQL Server because
/// those dialects say so. Matching ignores case and surrounding whitespace, and
/// an unknown name comes back with near-miss suggestions.
///
/// A dialect the host loaded at run time resolves the same way as one linked
/// in: both are read off the registry.
///
/// # Errors
///
/// [`ResolveError::UnknownDialect`], with suggestions, if no loaded dialect
/// answers to the name; [`ResolveError::AmbiguousName`] if two do.
///
/// # Examples
///
/// ```no_run
/// use razeri_plugin_api::{ResolveError, resolve_dialect_by_name};
///
/// # fn main() -> Result<(), ResolveError> {
/// // Aliases, canonical names and casing all resolve to the same dialect.
/// let dialect = resolve_dialect_by_name("pg")?;
/// println!("{}", dialect.info().name);
///
/// let dialect = resolve_dialect_by_name("SNOWFLAKE")?;
/// let dialect = resolve_dialect_by_name("sqlite")?;
/// # Ok(())
/// # }
/// ```
/// Resolve a dialect by string name, returning `None` on failure.
///
/// Convenience wrapper around [`resolve_dialect_by_name`] for callers that
/// prefer `Option` over `Result`.