diff --git a/Cargo.toml b/Cargo.toml index 5badd41..9755512 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ authors = ["Patrick Thach "] edition = "2021" name = "eventdbxjs" -version = "1.4.3" +version = "1.4.4" [lib] crate-type = ["cdylib", "rlib"] diff --git a/eventdbx.wasi-browser.js b/eventdbx.wasi-browser.js index 7f8eea8..41ed7b1 100644 --- a/eventdbx.wasi-browser.js +++ b/eventdbx.wasi-browser.js @@ -58,3 +58,5 @@ const { export default __napiModule.exports export const DbxClient = __napiModule.exports.DbxClient export const createClient = __napiModule.exports.createClient +export const PayloadMode = __napiModule.exports.PayloadMode +export const Priority = __napiModule.exports.Priority diff --git a/eventdbx.wasi.cjs b/eventdbx.wasi.cjs index a9b5df4..1b197a5 100644 --- a/eventdbx.wasi.cjs +++ b/eventdbx.wasi.cjs @@ -110,3 +110,5 @@ const { instance: __napiInstance, module: __wasiModule, napiModule: __napiModule module.exports = __napiModule.exports module.exports.DbxClient = __napiModule.exports.DbxClient module.exports.createClient = __napiModule.exports.createClient +module.exports.PayloadMode = __napiModule.exports.PayloadMode +module.exports.Priority = __napiModule.exports.Priority diff --git a/index.d.ts b/index.d.ts index 8d6516e..7adbce1 100644 --- a/index.d.ts +++ b/index.d.ts @@ -37,8 +37,8 @@ export declare class DbxClient { } export interface AppendOptions { - payload?: any - metadata?: any + payload?: JsonValue + metadata?: JsonValue note?: string token?: string publishTargets?: Array @@ -60,8 +60,8 @@ export interface ClientOptions { export interface CreateAggregateOptions { token?: string - payload?: any - metadata?: any + payload?: JsonValue + metadata?: JsonValue note?: string publishTargets?: Array } @@ -77,6 +77,29 @@ export interface GetSnapshotOptions { token?: string } +export type JsonPatch = + JsonPatchAddReplaceTest | JsonPatchRemove | JsonPatchMoveCopy + +export interface JsonPatchAddReplaceTest { + op: 'add' | 'replace' | 'test' + path: string + value: JsonValue +} + +export interface JsonPatchMoveCopy { + op: 'move' | 'copy' + from: string + path: string +} + +export interface JsonPatchRemove { + op: 'remove' + path: string +} + +export type JsonValue = + any + export interface ListSnapshotsOptions { aggregateType?: string aggregateId?: string @@ -100,16 +123,31 @@ export interface PageResult { } export interface PatchOptions { - metadata?: any + metadata?: JsonValue note?: string token?: string publishTargets?: Array } +export declare const enum PayloadMode { + All = 'all', + EventOnly = 'event-only', + StateOnly = 'state-only', + SchemaOnly = 'schema-only', + EventAndSchema = 'event-and-schema', + ExtensionsOnly = 'extensions-only' +} + +export declare const enum Priority { + High = 'high', + Normal = 'normal', + Low = 'low' +} + export interface PublishTargetOptions { plugin: string - mode?: string - priority?: string + mode?: PayloadMode + priority?: Priority } export interface RetryOptions { diff --git a/index.js b/index.js index 03bd177..4050a18 100644 --- a/index.js +++ b/index.js @@ -574,3 +574,5 @@ if (!nativeBinding) { module.exports = nativeBinding module.exports.DbxClient = nativeBinding.DbxClient module.exports.createClient = nativeBinding.createClient +module.exports.PayloadMode = nativeBinding.PayloadMode +module.exports.Priority = nativeBinding.Priority diff --git a/package.json b/package.json index a28456b..cb4bdca 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eventdbxjs", - "version": "1.4.3", + "version": "1.4.4", "description": "EventDBX client for Node.js", "main": "index.js", "types": "index.d.ts", diff --git a/src/lib.rs b/src/lib.rs index f8748a8..58468d6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,10 +19,89 @@ use crate::plugin_api::{ use napi::bindgen_prelude::*; use napi_derive::napi; use serde::Deserialize; -use serde_json::{json, Map as JsonMap, Value as JsonValue}; +use serde_json::{json, Map as JsonMap}; use tokio::sync::Mutex; use tokio::time::sleep; +#[napi(js_name = "JsonValue")] +pub type JsonValue = serde_json::Value; + +#[napi(object)] +pub struct JsonPatchAddReplaceTest { + #[napi(ts_type = "'add' | 'replace' | 'test'")] + pub op: String, + pub path: String, + #[napi(ts_type = "JsonValue")] + pub value: JsonValue, +} + +#[napi(object)] +pub struct JsonPatchRemove { + #[napi(ts_type = "'remove'")] + pub op: String, + pub path: String, +} + +#[napi(object)] +pub struct JsonPatchMoveCopy { + #[napi(ts_type = "'move' | 'copy'")] + pub op: String, + pub from: String, + pub path: String, +} + +#[napi(js_name = "JsonPatch")] +pub type JsonPatch = Either3; + +#[napi(string_enum)] +pub enum PayloadMode { + #[napi(value = "all")] + All, + #[napi(value = "event-only")] + EventOnly, + #[napi(value = "state-only")] + StateOnly, + #[napi(value = "schema-only")] + SchemaOnly, + #[napi(value = "event-and-schema")] + EventAndSchema, + #[napi(value = "extensions-only")] + ExtensionsOnly, +} + +impl PayloadMode { + fn as_str(&self) -> &'static str { + match self { + Self::All => "all", + Self::EventOnly => "event-only", + Self::StateOnly => "state-only", + Self::SchemaOnly => "schema-only", + Self::EventAndSchema => "event-and-schema", + Self::ExtensionsOnly => "extensions-only", + } + } +} + +#[napi(string_enum)] +pub enum Priority { + #[napi(value = "high")] + High, + #[napi(value = "normal")] + Normal, + #[napi(value = "low")] + Low, +} + +impl Priority { + fn as_str(&self) -> &'static str { + match self { + Self::High => "high", + Self::Normal => "normal", + Self::Low => "low", + } + } +} + #[derive(Clone, Debug)] struct ClientConfig { ip: String, @@ -219,7 +298,9 @@ pub struct PageResult { #[napi(object)] pub struct PublishTargetOptions { pub plugin: String, + #[napi(ts_type = "PayloadMode")] pub mode: Option, + #[napi(ts_type = "Priority")] pub priority: Option, } @@ -227,7 +308,9 @@ pub struct PublishTargetOptions { #[serde(rename_all = "camelCase")] #[napi(object)] pub struct AppendOptions { + #[napi(ts_type = "JsonValue")] pub payload: Option, + #[napi(ts_type = "JsonValue")] pub metadata: Option, pub note: Option, pub token: Option, @@ -236,6 +319,7 @@ pub struct AppendOptions { #[napi(object)] pub struct PatchOptions { + #[napi(ts_type = "JsonValue")] pub metadata: Option, pub note: Option, pub token: Option, @@ -247,7 +331,9 @@ pub struct PatchOptions { #[napi(object)] pub struct CreateAggregateOptions { pub token: Option, + #[napi(ts_type = "JsonValue")] pub payload: Option, + #[napi(ts_type = "JsonValue")] pub metadata: Option, pub note: Option, pub publish_targets: Option>, @@ -1099,6 +1185,57 @@ pub fn create_client(options: Option) -> DbxClient { DbxClient::new(options) } +fn normalize_payload_mode(value: Option) -> napi::Result> { + match value { + Some(value) => { + let normalized = value.trim().to_ascii_lowercase(); + if normalized.is_empty() { + return Ok(None); + } + let matched = match normalized.as_str() { + "all" => Some(PayloadMode::All), + "event-only" => Some(PayloadMode::EventOnly), + "state-only" => Some(PayloadMode::StateOnly), + "schema-only" => Some(PayloadMode::SchemaOnly), + "event-and-schema" => Some(PayloadMode::EventAndSchema), + "extensions-only" => Some(PayloadMode::ExtensionsOnly), + _ => { + return Err(napi_err( + Status::InvalidArg, + "publish target mode must be one of: all, event-only, state-only, schema-only, event-and-schema, extensions-only", + )) + } + }; + Ok(matched.map(|mode| mode.as_str().to_owned())) + } + None => Ok(None), + } +} + +fn normalize_priority(value: Option) -> napi::Result> { + match value { + Some(value) => { + let normalized = value.trim().to_ascii_lowercase(); + if normalized.is_empty() { + return Ok(None); + } + let matched = match normalized.as_str() { + "high" => Some(Priority::High), + "normal" => Some(Priority::Normal), + "low" => Some(Priority::Low), + _ => { + return Err(napi_err( + Status::InvalidArg, + "publish target priority must be one of: high, normal, low", + )) + } + }; + Ok(matched.map(|priority| priority.as_str().to_owned())) + } + None => Ok(None), + } +} + fn map_publish_targets( publish_targets: Option>, ) -> napi::Result>> { @@ -1114,51 +1251,8 @@ fn map_publish_targets( "publish target plugin is required", )); } - let mode = match target.mode { - Some(value) => { - let trimmed = value.trim(); - if trimmed.is_empty() { - None - } else { - let normalized = trimmed.to_ascii_lowercase(); - match normalized.as_str() { - "all" - | "event-only" - | "state-only" - | "schema-only" - | "event-and-schema" - | "extensions-only" => Some(normalized), - _ => { - return Err(napi_err( - Status::InvalidArg, - "publish target mode must be one of: all, event-only, state-only, schema-only, event-and-schema, extensions-only", - )) - } - } - } - } - None => None, - }; - let priority = match target.priority { - Some(value) => { - let trimmed = value.trim(); - if trimmed.is_empty() { - None - } else { - let normalized = trimmed.to_ascii_lowercase(); - match normalized.as_str() { - "high" | "normal" | "low" => Some(normalized), - _ => { - return Err(napi_err( - Status::InvalidArg, - "publish target priority must be one of: high, normal, low", - )) - } - } - } - } - None => None, - }; + let mode = normalize_payload_mode(target.mode)?; + let priority = normalize_priority(target.priority)?; Ok(PublishTargetSpec { plugin, mode,