commit 13deb322e30b9cc9250596cf61a0426a4758600f
parent 1050e18ed6f7f3aac073274f0048bf03ffe25a64
Author: triesap <tyson@radroots.org>
Date: Sun, 28 Jun 2026 00:23:51 +0000
ts: own wasm declarations with dto_bindgen
- Stop generating package src/index.ts barrels from the SDK xtask.
- Render WASM package declaration files through dto_bindgen TypeScript modules.
- Overwrite wasm-pack declaration output after every WASM generation run.
- Replace WASM declaration existence checks with TypeScript typechecks and stale-output guards.
Diffstat:
5 files changed, 1049 insertions(+), 32 deletions(-)
diff --git a/tools/sdk_xtask_import/src/check.rs b/tools/sdk_xtask_import/src/check.rs
@@ -8,6 +8,8 @@ use crate::{
FORBIDDEN_PACKAGE_NAMES, WasmPackageSpec, package_specs, validate_package_matrix,
wasm_package_specs,
},
+ ts::generated_header,
+ wasm_declarations::declaration_files,
};
pub fn check() -> Result<(), String> {
@@ -24,6 +26,7 @@ pub fn check() -> Result<(), String> {
if !index_path.is_file() {
return Err(format!("missing package index: {}", index_path.display()));
}
+ check_package_index(&index_path)?;
}
for spec in wasm_package_specs() {
check_wasm_package_surface(&root, *spec)?;
@@ -43,6 +46,18 @@ pub fn check() -> Result<(), String> {
Ok(())
}
+fn check_package_index(path: &Path) -> Result<(), String> {
+ let raw = fs::read_to_string(path)
+ .map_err(|error| format!("failed to read {}: {error}", path.display()))?;
+ if raw.starts_with(generated_header()) {
+ return Err(format!(
+ "package index must be handwritten source: {}",
+ path.display()
+ ));
+ }
+ Ok(())
+}
+
fn check_binding_crate_sources(root: &Path) -> Result<(), String> {
for spec in package_specs() {
let crate_src_dir = root.join(spec.crate_dir).join("src");
@@ -150,6 +165,22 @@ pub(crate) fn check_wasm_package_surface(root: &Path, spec: WasmPackageSpec) ->
));
}
}
+ check_wasm_declaration_files(&package_dir, spec)?;
+ Ok(())
+}
+
+fn check_wasm_declaration_files(package_dir: &Path, spec: WasmPackageSpec) -> Result<(), String> {
+ for expected in declaration_files(spec)? {
+ let path = package_dir.join(&expected.relative_path);
+ let actual = fs::read_to_string(&path)
+ .map_err(|error| format!("failed to read {}: {error}", path.display()))?;
+ if actual != expected.contents {
+ return Err(format!(
+ "stale dto_bindgen wasm declaration: {}",
+ path.display()
+ ));
+ }
+ }
Ok(())
}
@@ -271,7 +302,8 @@ mod tests {
use crate::package_matrix::{WasmPackageSpec, validate_package_matrix};
use super::{
- check_binding_crate_sources, check_no_typescript_files, check_wasm_package_surface,
+ check_binding_crate_sources, check_no_typescript_files, check_package_index,
+ check_wasm_package_surface,
};
#[test]
@@ -310,6 +342,23 @@ mod tests {
}
#[test]
+ fn rejects_generated_package_index_source() {
+ let root = test_root("generated_index");
+ let path = root.join("src/index.ts");
+ fs::create_dir_all(path.parent().expect("parent")).expect("create source directory");
+ fs::write(
+ &path,
+ "// @generated by cargo xtask generate ts\n// Do not edit by hand.\nexport {};\n",
+ )
+ .expect("write generated index");
+
+ let error = check_package_index(&path).expect_err("generated index rejected");
+
+ assert!(error.contains("package index must be handwritten source"));
+ let _ = fs::remove_dir_all(root);
+ }
+
+ #[test]
fn wasm_package_surface_requires_exported_dist_files() {
let root = test_root("wasm_surface");
let package_dir = root.join("packages").join("example-wasm");
@@ -347,10 +396,17 @@ mod tests {
assert!(missing.contains("example.d.ts"));
fs::write(
package_dir.join("dist").join("example.d.ts"),
- "export {};\n",
+ dto_declaration("example.d.ts"),
+ )
+ .expect("write d.ts");
+ fs::write(
+ package_dir.join("dist").join("example_bg.wasm.d.ts"),
+ dto_declaration("example_bg.wasm.d.ts"),
)
.expect("write d.ts");
- check_wasm_package_surface(&root, spec).expect("surface is complete");
+ let error = check_wasm_package_surface(&root, spec)
+ .expect_err("unknown declaration inventory rejected");
+ assert!(error.contains("missing wasm declaration inventory"));
let _ = fs::remove_dir_all(root);
}
@@ -374,9 +430,14 @@ mod tests {
fs::write(package_dir.join("dist").join("example.js"), "export {};\n").expect("write js");
fs::write(
package_dir.join("dist").join("example.d.ts"),
- "export {};\n",
+ dto_declaration("example.d.ts"),
)
.expect("write d.ts");
+ fs::write(
+ package_dir.join("dist").join("example_bg.wasm.d.ts"),
+ dto_declaration("example_bg.wasm.d.ts"),
+ )
+ .expect("write wasm d.ts");
fs::write(package_dir.join("dist").join("package.json"), "{}\n")
.expect("write forbidden manifest");
let spec = WasmPackageSpec {
@@ -418,9 +479,14 @@ mod tests {
fs::write(package_dir.join("dist").join("example.js"), "export {};\n").expect("write js");
fs::write(
package_dir.join("dist").join("example.d.ts"),
- "export {};\n",
+ dto_declaration("example.d.ts"),
)
.expect("write d.ts");
+ fs::write(
+ package_dir.join("dist").join("example_bg.wasm.d.ts"),
+ dto_declaration("example_bg.wasm.d.ts"),
+ )
+ .expect("write wasm d.ts");
let spec = WasmPackageSpec {
key: "example",
crate_name: "radroots_example_wasm",
@@ -450,4 +516,10 @@ mod tests {
let _ = fs::remove_dir_all(&root);
root
}
+
+ fn dto_declaration(name: &str) -> String {
+ format!(
+ "// @generated by cargo xtask generate wasm via dto_bindgen\n// Do not edit by hand.\nexport type Generated = \"{name}\";\n"
+ )
+ }
}
diff --git a/tools/sdk_xtask_import/src/main.rs b/tools/sdk_xtask_import/src/main.rs
@@ -11,6 +11,7 @@ mod output;
mod package_matrix;
mod ts;
mod wasm;
+mod wasm_declarations;
enum CommandAction<'a> {
GenerateTs,
diff --git a/tools/sdk_xtask_import/src/output.rs b/tools/sdk_xtask_import/src/output.rs
@@ -71,10 +71,6 @@ impl PackageOutput {
relative_path: format!("src/generated/{}", manifest_file_name()),
contents: render_manifest(self.spec),
});
- files.push(GeneratedFile {
- relative_path: "src/index.ts".to_owned(),
- contents: render_index(self),
- });
files
}
}
@@ -195,23 +191,6 @@ fn render_manifest(spec: PackageSpec) -> String {
)
}
-fn render_index(output: &PackageOutput) -> String {
- let mut lines = Vec::new();
- if output.types_ts.is_some() {
- lines.push("export * from \"./generated/types.js\";");
- }
- if output.constants_ts.is_some() {
- lines.push("export * from \"./generated/constants.js\";");
- }
- if output.kinds_ts.is_some() {
- lines.push("export * from \"./generated/kinds.js\";");
- }
- if lines.is_empty() {
- lines.push("export {};");
- }
- format!("{}\n", lines.join("\n"))
-}
-
#[cfg(test)]
mod tests {
use super::{PackageOutput, TsSource, package_outputs, render_ts};
@@ -273,7 +252,7 @@ mod tests {
}
#[test]
- fn dto_registry_source_uses_package_shell() {
+ fn dto_registry_source_uses_generated_package_files() {
let output = PackageOutput {
spec: package_specs()[0],
types_ts: Some(TsSource::DtoRegistry(DtoTypesModule::new(
@@ -296,17 +275,31 @@ mod tests {
.iter()
.find(|file| file.relative_path == "src/generated/sdk-manifest.json")
.expect("manifest file");
- let index = files
- .iter()
- .find(|file| file.relative_path == "src/index.ts")
- .expect("index file");
assert_eq!(
types.contents,
"// @generated by cargo xtask generate ts\n// Do not edit by hand.\nimport type { LocalPrelude } from \"@radroots/local\";\nimport type { ExternalThing } from \"@radroots/external-bindings\";\n\nexport type SyntheticThing = { external: ExternalThing, };\n"
);
assert!(manifest.contents.contains("\"generated\": true"));
- assert_eq!(index.contents, "export * from \"./generated/types.js\";\n");
+ assert!(
+ !files
+ .iter()
+ .any(|file| file.relative_path == "src/index.ts")
+ );
+ }
+
+ #[test]
+ fn package_outputs_do_not_generate_package_indices() {
+ for output in package_outputs().expect("package outputs") {
+ assert!(
+ !output
+ .files()
+ .iter()
+ .any(|file| file.relative_path == "src/index.ts"),
+ "{} index must remain handwritten source",
+ output.spec.package_name
+ );
+ }
}
#[test]
diff --git a/tools/sdk_xtask_import/src/wasm.rs b/tools/sdk_xtask_import/src/wasm.rs
@@ -9,6 +9,7 @@ use crate::{
check::check_wasm_package_surface,
fs::workspace_root,
package_matrix::{WasmPackageSpec, validate_package_matrix, wasm_package_specs},
+ wasm_declarations::write_declaration_files,
};
const WASM_TARGET: &str = "wasm32-unknown-unknown";
@@ -46,6 +47,7 @@ pub fn generate(args: &[String]) -> Result<(), String> {
spec.key, spec.package_name, spec.key
));
}
+ write_declaration_files(&root, spec)?;
check_wasm_package_surface(&root, spec)?;
println!("generated wasm package {}", spec.package_name);
}
diff --git a/tools/sdk_xtask_import/src/wasm_declarations.rs b/tools/sdk_xtask_import/src/wasm_declarations.rs
@@ -0,0 +1,949 @@
+use std::path::Path;
+
+use dto_bindgen_backend_ts::{
+ TypeScriptDeclaration, TypeScriptModule, TypeScriptParameter, TypeScriptProperty,
+ TypeScriptType, TypeScriptValue,
+};
+
+use crate::package_matrix::WasmPackageSpec;
+
+const WASM_DECLARATION_HEADER: &str =
+ "// @generated by cargo xtask generate wasm via dto_bindgen\n// Do not edit by hand.\n";
+
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct WasmDeclarationFile {
+ pub relative_path: String,
+ pub contents: String,
+}
+
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+struct WasmDeclarationInventory {
+ public_functions: &'static [WasmPublicFunction],
+ support_exports: &'static [WasmSupportExport],
+}
+
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+struct WasmPublicFunction {
+ name: &'static str,
+ parameter: Option<&'static str>,
+ return_kind: WasmReturnKind,
+ low_level: LowLevelSignature,
+}
+
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+enum WasmReturnKind {
+ String,
+ Any,
+ Void,
+}
+
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+struct LowLevelSignature {
+ parameters: usize,
+ returns: usize,
+}
+
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+struct WasmSupportExport {
+ name: &'static str,
+ export_type: WasmSupportExportType,
+}
+
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+enum WasmSupportExportType {
+ Memory,
+ Table,
+ Function(LowLevelSignature),
+ NumberFunction(usize),
+}
+
+macro_rules! public_function {
+ ($name:literal, $parameter:expr, $return_kind:ident, $low_parameters:literal, $low_returns:literal) => {
+ WasmPublicFunction {
+ name: $name,
+ parameter: $parameter,
+ return_kind: WasmReturnKind::$return_kind,
+ low_level: LowLevelSignature {
+ parameters: $low_parameters,
+ returns: $low_returns,
+ },
+ }
+ };
+}
+
+macro_rules! memory_export {
+ () => {
+ WasmSupportExport {
+ name: "memory",
+ export_type: WasmSupportExportType::Memory,
+ }
+ };
+}
+
+macro_rules! table_export {
+ ($name:literal) => {
+ WasmSupportExport {
+ name: $name,
+ export_type: WasmSupportExportType::Table,
+ }
+ };
+}
+
+macro_rules! void_function_export {
+ ($name:literal, $parameters:literal) => {
+ WasmSupportExport {
+ name: $name,
+ export_type: WasmSupportExportType::Function(LowLevelSignature {
+ parameters: $parameters,
+ returns: 0,
+ }),
+ }
+ };
+}
+
+macro_rules! number_function_export {
+ ($name:literal, $parameters:literal) => {
+ WasmSupportExport {
+ name: $name,
+ export_type: WasmSupportExportType::NumberFunction($parameters),
+ }
+ };
+}
+
+pub fn write_declaration_files(root: &Path, spec: WasmPackageSpec) -> Result<(), String> {
+ let package_dir = root.join(spec.package_dir);
+ for file in declaration_files(spec)? {
+ crate::fs::write_if_changed(&package_dir.join(&file.relative_path), &file.contents)?;
+ }
+ Ok(())
+}
+
+pub fn declaration_files(spec: WasmPackageSpec) -> Result<Vec<WasmDeclarationFile>, String> {
+ let inventory = inventory(spec)?;
+ Ok(vec![
+ WasmDeclarationFile {
+ relative_path: format!("dist/{}.d.ts", spec.out_name),
+ contents: render_declaration_module(primary_module(spec, inventory)),
+ },
+ WasmDeclarationFile {
+ relative_path: format!("dist/{}_bg.wasm.d.ts", spec.out_name),
+ contents: render_declaration_module(sidecar_module(spec, inventory)),
+ },
+ ])
+}
+
+fn inventory(spec: WasmPackageSpec) -> Result<WasmDeclarationInventory, String> {
+ match spec.key {
+ "events_codec" => Ok(WasmDeclarationInventory {
+ public_functions: EVENTS_CODEC_FUNCTIONS,
+ support_exports: EVENTS_CODEC_SUPPORT_EXPORTS,
+ }),
+ "replica_db" => Ok(WasmDeclarationInventory {
+ public_functions: REPLICA_DB_FUNCTIONS,
+ support_exports: SQL_WASM_SUPPORT_EXPORTS,
+ }),
+ "replica_sync" => Ok(WasmDeclarationInventory {
+ public_functions: REPLICA_SYNC_FUNCTIONS,
+ support_exports: SQL_WASM_SUPPORT_EXPORTS,
+ }),
+ _ => Err(format!(
+ "missing wasm declaration inventory for {}",
+ spec.key
+ )),
+ }
+}
+
+fn primary_module(spec: WasmPackageSpec, inventory: WasmDeclarationInventory) -> TypeScriptModule {
+ let mut module = TypeScriptModule::new(format!("dist/{}.d.ts", spec.out_name));
+ for function in inventory.public_functions {
+ module.push_declaration(TypeScriptDeclaration::function(
+ function.name,
+ public_parameters(function.parameter),
+ public_return_type(function.return_kind),
+ ));
+ }
+ module.push_declaration(TypeScriptDeclaration::type_alias(
+ "InitInput",
+ init_input_type(),
+ ));
+ module.push_declaration(TypeScriptDeclaration::type_alias(
+ "InitOutput",
+ init_output_type(inventory),
+ ));
+ module.push_declaration(TypeScriptDeclaration::type_alias(
+ "SyncInitInput",
+ sync_init_input_type(),
+ ));
+ module.push_declaration(TypeScriptDeclaration::function(
+ "initSync",
+ vec![TypeScriptParameter::new(
+ "module",
+ TypeScriptType::union(vec![
+ TypeScriptType::object(vec![TypeScriptProperty::new(
+ "module",
+ TypeScriptType::named("SyncInitInput"),
+ )]),
+ TypeScriptType::named("SyncInitInput"),
+ ]),
+ )],
+ TypeScriptType::named("InitOutput"),
+ ));
+ module.push_declaration(TypeScriptDeclaration::default_function(
+ "__wbg_init",
+ vec![
+ TypeScriptParameter::new(
+ "module_or_path",
+ TypeScriptType::union(vec![
+ TypeScriptType::object(vec![TypeScriptProperty::new(
+ "module_or_path",
+ TypeScriptType::union(vec![
+ TypeScriptType::named("InitInput"),
+ promise_of(TypeScriptType::named("InitInput")),
+ ]),
+ )]),
+ TypeScriptType::named("InitInput"),
+ promise_of(TypeScriptType::named("InitInput")),
+ ]),
+ )
+ .optional(),
+ ],
+ promise_of(TypeScriptType::named("InitOutput")),
+ ));
+ module
+}
+
+fn sidecar_module(spec: WasmPackageSpec, inventory: WasmDeclarationInventory) -> TypeScriptModule {
+ let mut module = TypeScriptModule::new(format!("dist/{}_bg.wasm.d.ts", spec.out_name));
+ for export in inventory.support_exports {
+ if matches!(export.export_type, WasmSupportExportType::Memory) {
+ module.push_declaration(support_export_declaration(*export));
+ }
+ }
+ for function in inventory.public_functions {
+ module.push_declaration(TypeScriptDeclaration::constant(
+ function.name,
+ Some(low_level_function_type(function.low_level)),
+ TypeScriptValue::string(""),
+ ));
+ }
+ for export in inventory.support_exports {
+ if !matches!(export.export_type, WasmSupportExportType::Memory) {
+ module.push_declaration(support_export_declaration(*export));
+ }
+ }
+ module
+}
+
+fn render_declaration_module(module: TypeScriptModule) -> String {
+ let mut rendered = String::from(WASM_DECLARATION_HEADER);
+ rendered.push_str(&module.render_declaration());
+ rendered
+}
+
+fn public_parameters(parameter: Option<&'static str>) -> Vec<TypeScriptParameter> {
+ parameter
+ .map(|name| vec![TypeScriptParameter::new(name, TypeScriptType::String)])
+ .unwrap_or_default()
+}
+
+fn public_return_type(kind: WasmReturnKind) -> TypeScriptType {
+ match kind {
+ WasmReturnKind::String => TypeScriptType::String,
+ WasmReturnKind::Any => TypeScriptType::Any,
+ WasmReturnKind::Void => TypeScriptType::Void,
+ }
+}
+
+fn init_input_type() -> TypeScriptType {
+ TypeScriptType::union(vec![
+ TypeScriptType::named("RequestInfo"),
+ TypeScriptType::named("URL"),
+ TypeScriptType::named("Response"),
+ TypeScriptType::named("BufferSource"),
+ TypeScriptType::named("WebAssembly.Module"),
+ ])
+}
+
+fn sync_init_input_type() -> TypeScriptType {
+ TypeScriptType::union(vec![
+ TypeScriptType::named("BufferSource"),
+ TypeScriptType::named("WebAssembly.Module"),
+ ])
+}
+
+fn init_output_type(inventory: WasmDeclarationInventory) -> TypeScriptType {
+ let mut properties = vec![TypeScriptProperty::new("memory", memory_type()).readonly()];
+ properties.extend(inventory.public_functions.iter().map(|function| {
+ TypeScriptProperty::new(function.name, low_level_function_type(function.low_level))
+ .readonly()
+ }));
+ properties.extend(
+ inventory
+ .support_exports
+ .iter()
+ .filter(|export| !matches!(export.export_type, WasmSupportExportType::Memory))
+ .map(|export| {
+ TypeScriptProperty::new(export.name, support_export_type(*export)).readonly()
+ }),
+ );
+ TypeScriptType::object(properties)
+}
+
+fn support_export_declaration(export: WasmSupportExport) -> TypeScriptDeclaration {
+ TypeScriptDeclaration::constant(
+ export.name,
+ Some(support_export_type(export)),
+ TypeScriptValue::string(""),
+ )
+}
+
+fn support_export_type(export: WasmSupportExport) -> TypeScriptType {
+ match export.export_type {
+ WasmSupportExportType::Memory => memory_type(),
+ WasmSupportExportType::Table => TypeScriptType::named("WebAssembly.Table"),
+ WasmSupportExportType::Function(signature) => low_level_function_type(signature),
+ WasmSupportExportType::NumberFunction(parameters) => {
+ low_level_number_function_type(parameters)
+ }
+ }
+}
+
+fn memory_type() -> TypeScriptType {
+ TypeScriptType::named("WebAssembly.Memory")
+}
+
+fn low_level_number_function_type(parameters: usize) -> TypeScriptType {
+ TypeScriptType::function(number_parameters(parameters), TypeScriptType::Number)
+}
+
+fn low_level_function_type(signature: LowLevelSignature) -> TypeScriptType {
+ TypeScriptType::function(
+ number_parameters(signature.parameters),
+ low_level_return_type(signature.returns),
+ )
+}
+
+fn number_parameters(count: usize) -> Vec<TypeScriptParameter> {
+ (0..count)
+ .map(|index| {
+ TypeScriptParameter::new(low_level_parameter_name(index), TypeScriptType::Number)
+ })
+ .collect()
+}
+
+fn low_level_parameter_name(index: usize) -> String {
+ match index {
+ 0 => "a".to_owned(),
+ 1 => "b".to_owned(),
+ 2 => "c".to_owned(),
+ 3 => "d".to_owned(),
+ _ => format!("arg{index}"),
+ }
+}
+
+fn low_level_return_type(count: usize) -> TypeScriptType {
+ match count {
+ 0 => TypeScriptType::Void,
+ 1 => TypeScriptType::Number,
+ _ => TypeScriptType::tuple(vec![TypeScriptType::Number; count]),
+ }
+}
+
+fn promise_of(type_expr: TypeScriptType) -> TypeScriptType {
+ TypeScriptType::generic("Promise", vec![type_expr])
+}
+
+const EVENTS_CODEC_FUNCTIONS: &[WasmPublicFunction] = &[
+ public_function!("article_tags", Some("article_json"), String, 2, 4),
+ public_function!("calendar_date_event_tags", Some("event_json"), String, 2, 4),
+ public_function!("calendar_event_rsvp_tags", Some("rsvp_json"), String, 2, 4),
+ public_function!("calendar_tags", Some("calendar_json"), String, 2, 4),
+ public_function!("calendar_time_event_tags", Some("event_json"), String, 2, 4),
+ public_function!("comment_tags", Some("comment_json"), String, 2, 4),
+ public_function!("coop_tags", Some("coop_json"), String, 2, 4),
+ public_function!("document_tags", Some("document_json"), String, 2, 4),
+ public_function!("farm_crdt_change_tags", Some("input_json"), String, 2, 4),
+ public_function!("farm_file_metadata_tags", Some("file_json"), String, 2, 4),
+ public_function!("farm_tags", Some("farm_json"), String, 2, 4),
+ public_function!(
+ "farm_workspace_manifest_tags",
+ Some("workspace_json"),
+ String,
+ 2,
+ 4
+ ),
+ public_function!("file_metadata_tags", Some("metadata_json"), String, 2, 4),
+ public_function!("follow_tags", Some("follow_json"), String, 2, 4),
+ public_function!("generic_repost_tags", Some("repost_json"), String, 2, 4),
+ public_function!("gift_wrap_tags", Some("gift_wrap_json"), String, 2, 4),
+ public_function!("group_admins_tags", Some("group_json"), String, 2, 4),
+ public_function!("group_create_group_tags", Some("group_json"), String, 2, 4),
+ public_function!("group_create_invite_tags", Some("group_json"), String, 2, 4),
+ public_function!("group_delete_event_tags", Some("group_json"), String, 2, 4),
+ public_function!("group_delete_group_tags", Some("group_json"), String, 2, 4),
+ public_function!("group_edit_metadata_tags", Some("group_json"), String, 2, 4),
+ public_function!("group_join_request_tags", Some("group_json"), String, 2, 4),
+ public_function!("group_leave_request_tags", Some("group_json"), String, 2, 4),
+ public_function!("group_members_tags", Some("group_json"), String, 2, 4),
+ public_function!("group_metadata_tags", Some("group_json"), String, 2, 4),
+ public_function!("group_put_user_tags", Some("group_json"), String, 2, 4),
+ public_function!("group_remove_user_tags", Some("group_json"), String, 2, 4),
+ public_function!("group_roles_tags", Some("group_json"), String, 2, 4),
+ public_function!("http_auth_tags", Some("auth_json"), String, 2, 4),
+ public_function!("job_feedback_tags", Some("job_json"), String, 2, 4),
+ public_function!("job_request_tags", Some("job_json"), String, 2, 4),
+ public_function!("job_result_tags", Some("job_json"), String, 2, 4),
+ public_function!("list_set_tags", Some("list_json"), String, 2, 4),
+ public_function!("list_tags", Some("list_json"), String, 2, 4),
+ public_function!("listing_tags", Some("listing_json"), String, 2, 4),
+ public_function!("listing_tags_full", Some("listing_json"), String, 2, 4),
+ public_function!("message_file_tags", Some("message_json"), String, 2, 4),
+ public_function!("message_tags", Some("message_json"), String, 2, 4),
+ public_function!("plot_tags", Some("plot_json"), String, 2, 4),
+ public_function!("post_tags", Some("post_json"), String, 2, 4),
+ public_function!("reaction_tags", Some("reaction_json"), String, 2, 4),
+ public_function!("relay_auth_tags", Some("auth_json"), String, 2, 4),
+ public_function!("report_tags", Some("report_json"), String, 2, 4),
+ public_function!("repost_tags", Some("repost_json"), String, 2, 4),
+ public_function!("seal_tags", Some("seal_json"), String, 2, 4),
+];
+
+const EVENTS_CODEC_SUPPORT_EXPORTS: &[WasmSupportExport] = &[
+ memory_export!(),
+ table_export!("__wbindgen_externrefs"),
+ number_function_export!("__wbindgen_malloc", 2),
+ number_function_export!("__wbindgen_realloc", 4),
+ void_function_export!("__externref_table_dealloc", 1),
+ void_function_export!("__wbindgen_free", 3),
+ void_function_export!("__wbindgen_start", 0),
+];
+
+const REPLICA_DB_FUNCTIONS: &[WasmPublicFunction] = &[
+ public_function!("replica_db_export_begin", None, Any, 0, 3),
+ public_function!("replica_db_export_finish", None, Void, 0, 2),
+ public_function!("replica_db_export_json", None, Any, 0, 3),
+ public_function!("replica_db_farm_create", Some("opts_json"), Any, 2, 3),
+ public_function!("replica_db_farm_delete", Some("opts_json"), Any, 2, 3),
+ public_function!("replica_db_farm_find_many", Some("opts_json"), Any, 2, 3),
+ public_function!("replica_db_farm_find_one", Some("opts_json"), Any, 2, 3),
+ public_function!(
+ "replica_db_farm_gcs_location_create",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_farm_gcs_location_delete",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_farm_gcs_location_find_many",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_farm_gcs_location_find_one",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_farm_gcs_location_update",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_farm_member_claim_create",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_farm_member_claim_delete",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_farm_member_claim_find_many",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_farm_member_claim_find_one",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_farm_member_claim_update",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_farm_member_create",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_farm_member_delete",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_farm_member_find_many",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_farm_member_find_one",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_farm_member_update",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!("replica_db_farm_tag_create", Some("opts_json"), Any, 2, 3),
+ public_function!("replica_db_farm_tag_delete", Some("opts_json"), Any, 2, 3),
+ public_function!(
+ "replica_db_farm_tag_find_many",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!("replica_db_farm_tag_find_one", Some("opts_json"), Any, 2, 3),
+ public_function!("replica_db_farm_tag_update", Some("opts_json"), Any, 2, 3),
+ public_function!(
+ "replica_db_gcs_location_create",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_gcs_location_delete",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_gcs_location_find_many",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_gcs_location_find_one",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_gcs_location_update",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!("replica_db_import_json", Some("dump_json"), Void, 2, 2),
+ public_function!("replica_db_log_error_create", Some("opts_json"), Any, 2, 3),
+ public_function!("replica_db_log_error_delete", Some("opts_json"), Any, 2, 3),
+ public_function!(
+ "replica_db_log_error_find_many",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_log_error_find_one",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!("replica_db_log_error_update", Some("opts_json"), Any, 2, 3),
+ public_function!(
+ "replica_db_media_image_create",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_media_image_delete",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_media_image_find_many",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_media_image_find_one",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_media_image_update",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_nostr_event_head_create",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_nostr_event_head_delete",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_nostr_event_head_find_many",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_nostr_event_head_find_one",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_nostr_event_head_update",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_nostr_profile_create",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_nostr_profile_delete",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_nostr_profile_find_many",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_nostr_profile_find_one",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_nostr_profile_relay_set",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_nostr_profile_relay_unset",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_nostr_profile_update",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_nostr_relay_create",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_nostr_relay_delete",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_nostr_relay_find_many",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_nostr_relay_find_one",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_nostr_relay_update",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!("replica_db_plot_create", Some("opts_json"), Any, 2, 3),
+ public_function!("replica_db_plot_delete", Some("opts_json"), Any, 2, 3),
+ public_function!("replica_db_plot_find_many", Some("opts_json"), Any, 2, 3),
+ public_function!("replica_db_plot_find_one", Some("opts_json"), Any, 2, 3),
+ public_function!(
+ "replica_db_plot_gcs_location_create",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_plot_gcs_location_delete",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_plot_gcs_location_find_many",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_plot_gcs_location_find_one",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_plot_gcs_location_update",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!("replica_db_plot_tag_create", Some("opts_json"), Any, 2, 3),
+ public_function!("replica_db_plot_tag_delete", Some("opts_json"), Any, 2, 3),
+ public_function!(
+ "replica_db_plot_tag_find_many",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!("replica_db_plot_tag_find_one", Some("opts_json"), Any, 2, 3),
+ public_function!("replica_db_plot_tag_update", Some("opts_json"), Any, 2, 3),
+ public_function!("replica_db_reset_database", None, Void, 0, 2),
+ public_function!("replica_db_run_migrations", None, Void, 0, 2),
+ public_function!(
+ "replica_db_trade_product_create",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_trade_product_delete",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_trade_product_find_many",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_trade_product_find_one",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_trade_product_location_set",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_trade_product_location_unset",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_trade_product_media_set",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_trade_product_media_unset",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+ public_function!(
+ "replica_db_trade_product_update",
+ Some("opts_json"),
+ Any,
+ 2,
+ 3
+ ),
+];
+
+const REPLICA_SYNC_FUNCTIONS: &[WasmPublicFunction] = &[
+ public_function!("replica_sync_ingest_event", Some("event_json"), Any, 2, 3),
+ public_function!("replica_sync_sync_all", Some("request_json"), Any, 2, 3),
+];
+
+const SQL_WASM_SUPPORT_EXPORTS: &[WasmSupportExport] = &[
+ memory_export!(),
+ number_function_export!("__wbindgen_malloc", 2),
+ number_function_export!("__wbindgen_realloc", 4),
+ void_function_export!("__wbindgen_exn_store", 1),
+ number_function_export!("__externref_table_alloc", 0),
+ table_export!("__wbindgen_externrefs"),
+ void_function_export!("__externref_table_dealloc", 1),
+ void_function_export!("__wbindgen_start", 0),
+];
+
+#[cfg(test)]
+mod tests {
+ use crate::package_matrix::wasm_package_specs;
+
+ use super::{WASM_DECLARATION_HEADER, declaration_files};
+
+ #[test]
+ fn declaration_files_are_dto_owned_and_cover_primary_and_sidecar_paths() {
+ for spec in wasm_package_specs() {
+ let files = declaration_files(*spec).expect("declaration files");
+ assert_eq!(files.len(), 2);
+ assert!(
+ files
+ .iter()
+ .any(|file| file.relative_path == format!("dist/{}.d.ts", spec.out_name))
+ );
+ assert!(
+ files.iter().any(
+ |file| file.relative_path == format!("dist/{}_bg.wasm.d.ts", spec.out_name)
+ )
+ );
+ for file in files {
+ assert!(file.contents.starts_with(WASM_DECLARATION_HEADER));
+ assert!(!file.contents.contains("tslint:disable"));
+ assert!(!file.contents.contains("eslint-disable"));
+ }
+ }
+ }
+
+ #[test]
+ fn generated_declarations_include_public_wasm_entrypoints() {
+ let specs = wasm_package_specs();
+ let events = declaration_files(specs[0]).expect("events declarations");
+ assert!(events[0].contents.contains("export function listing_tags"));
+ assert!(
+ events[1]
+ .contents
+ .contains("export declare const listing_tags")
+ );
+
+ let replica_db = declaration_files(specs[1]).expect("replica db declarations");
+ assert!(
+ replica_db[0]
+ .contents
+ .contains("export function replica_db_farm_create")
+ );
+ assert!(
+ replica_db[1]
+ .contents
+ .contains("export declare const replica_db_farm_create")
+ );
+
+ let replica_sync = declaration_files(specs[2]).expect("replica sync declarations");
+ assert!(
+ replica_sync[0]
+ .contents
+ .contains("export function replica_sync_sync_all")
+ );
+ assert!(
+ replica_sync[1]
+ .contents
+ .contains("export declare const replica_sync_sync_all")
+ );
+ }
+}