diff --git a/packages/backend-rs/Makefile b/packages/backend-rs/Makefile
index ddf680da4b..9e53b37837 100644
--- a/packages/backend-rs/Makefile
+++ b/packages/backend-rs/Makefile
@@ -16,11 +16,11 @@ regenerate-entities:
 	for file in src/model/entity/*; do \
 	  base=$$(basename -- "$${file}"); \
 	  jsname=$$(printf '%s\n' "$${base%.*}" | perl -pe 's/(^|_)./uc($$&)/ge;s/_//g'); \
-	  attribute=$$(printf 'cfg_attr(feature = "napi", napi_derive::napi(object, js_name = "%s", use_nullable = true))' "$${jsname}"); \
+	  attribute=$$(printf 'macros::export(object, js_name = "%s")' "$${jsname}"); \
 	  sed -i "s/NAPI_EXTRA_ATTR_PLACEHOLDER/$${attribute}/" "$${file}"; \
 		sed -i 's/#\[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)\]/#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]\n#[serde(rename_all = "camelCase")]/' "$${file}"; \
 	done
-	sed -i 's/#\[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)\]/#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]\n#[serde(rename_all = "camelCase")]\n#[cfg_attr(not(feature = "napi"), derive(Clone))]\n#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]/' \
+	sed -i 's/#\[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)\]/#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]\n#[serde(rename_all = "camelCase")]\n#[macros::derive_clone_and_export(string_enum = "camelCase")]/' \
 	  src/model/entity/sea_orm_active_enums.rs
 	cargo fmt --all --
 
diff --git a/packages/backend-rs/src/model/entity/abuse_user_report.rs b/packages/backend-rs/src/model/entity/abuse_user_report.rs
index 412af368c0..70ab552eaa 100644
--- a/packages/backend-rs/src/model/entity/abuse_user_report.rs
+++ b/packages/backend-rs/src/model/entity/abuse_user_report.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "abuse_user_report")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "AbuseUserReport", use_nullable = true)
-)]
+#[macros::export(object, js_name = "AbuseUserReport")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/access_token.rs b/packages/backend-rs/src/model/entity/access_token.rs
index edfeb9b34c..e3767b4408 100644
--- a/packages/backend-rs/src/model/entity/access_token.rs
+++ b/packages/backend-rs/src/model/entity/access_token.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "access_token")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "AccessToken", use_nullable = true)
-)]
+#[macros::export(object, js_name = "AccessToken")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/ad.rs b/packages/backend-rs/src/model/entity/ad.rs
index 6431d04f13..54495037d4 100644
--- a/packages/backend-rs/src/model/entity/ad.rs
+++ b/packages/backend-rs/src/model/entity/ad.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "ad")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "Ad", use_nullable = true)
-)]
+#[macros::export(object, js_name = "Ad")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/announcement.rs b/packages/backend-rs/src/model/entity/announcement.rs
index 30cfc5077b..750c8d17a7 100644
--- a/packages/backend-rs/src/model/entity/announcement.rs
+++ b/packages/backend-rs/src/model/entity/announcement.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "announcement")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "Announcement", use_nullable = true)
-)]
+#[macros::export(object, js_name = "Announcement")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/announcement_read.rs b/packages/backend-rs/src/model/entity/announcement_read.rs
index bf83a88a92..169b6c9bd1 100644
--- a/packages/backend-rs/src/model/entity/announcement_read.rs
+++ b/packages/backend-rs/src/model/entity/announcement_read.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "announcement_read")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "AnnouncementRead", use_nullable = true)
-)]
+#[macros::export(object, js_name = "AnnouncementRead")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/antenna.rs b/packages/backend-rs/src/model/entity/antenna.rs
index 54b5e1fafa..45d40f10b7 100644
--- a/packages/backend-rs/src/model/entity/antenna.rs
+++ b/packages/backend-rs/src/model/entity/antenna.rs
@@ -7,10 +7,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "antenna")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "Antenna", use_nullable = true)
-)]
+#[macros::export(object, js_name = "Antenna")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/app.rs b/packages/backend-rs/src/model/entity/app.rs
index b00a3c6022..06c1d50817 100644
--- a/packages/backend-rs/src/model/entity/app.rs
+++ b/packages/backend-rs/src/model/entity/app.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "app")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "App", use_nullable = true)
-)]
+#[macros::export(object, js_name = "App")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/attestation_challenge.rs b/packages/backend-rs/src/model/entity/attestation_challenge.rs
index 09f67bb8dd..ca3804ac04 100644
--- a/packages/backend-rs/src/model/entity/attestation_challenge.rs
+++ b/packages/backend-rs/src/model/entity/attestation_challenge.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "attestation_challenge")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "AttestationChallenge", use_nullable = true)
-)]
+#[macros::export(object, js_name = "AttestationChallenge")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/auth_session.rs b/packages/backend-rs/src/model/entity/auth_session.rs
index c9fd51ddfc..1dc6acd414 100644
--- a/packages/backend-rs/src/model/entity/auth_session.rs
+++ b/packages/backend-rs/src/model/entity/auth_session.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "auth_session")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "AuthSession", use_nullable = true)
-)]
+#[macros::export(object, js_name = "AuthSession")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/blocking.rs b/packages/backend-rs/src/model/entity/blocking.rs
index fdd24d37ba..3a9a0753d1 100644
--- a/packages/backend-rs/src/model/entity/blocking.rs
+++ b/packages/backend-rs/src/model/entity/blocking.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "blocking")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "Blocking", use_nullable = true)
-)]
+#[macros::export(object, js_name = "Blocking")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/channel.rs b/packages/backend-rs/src/model/entity/channel.rs
index ae1a469a43..221a72bc4c 100644
--- a/packages/backend-rs/src/model/entity/channel.rs
+++ b/packages/backend-rs/src/model/entity/channel.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "channel")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "Channel", use_nullable = true)
-)]
+#[macros::export(object, js_name = "Channel")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/channel_following.rs b/packages/backend-rs/src/model/entity/channel_following.rs
index 572489ea4b..9be21b8511 100644
--- a/packages/backend-rs/src/model/entity/channel_following.rs
+++ b/packages/backend-rs/src/model/entity/channel_following.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "channel_following")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "ChannelFollowing", use_nullable = true)
-)]
+#[macros::export(object, js_name = "ChannelFollowing")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/channel_note_pining.rs b/packages/backend-rs/src/model/entity/channel_note_pining.rs
index 9fdaeffe05..d03ee961dd 100644
--- a/packages/backend-rs/src/model/entity/channel_note_pining.rs
+++ b/packages/backend-rs/src/model/entity/channel_note_pining.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "channel_note_pining")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "ChannelNotePining", use_nullable = true)
-)]
+#[macros::export(object, js_name = "ChannelNotePining")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/clip.rs b/packages/backend-rs/src/model/entity/clip.rs
index 36e1ced5f3..fcd5b11315 100644
--- a/packages/backend-rs/src/model/entity/clip.rs
+++ b/packages/backend-rs/src/model/entity/clip.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "clip")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "Clip", use_nullable = true)
-)]
+#[macros::export(object, js_name = "Clip")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/clip_note.rs b/packages/backend-rs/src/model/entity/clip_note.rs
index adab667e74..9cce432242 100644
--- a/packages/backend-rs/src/model/entity/clip_note.rs
+++ b/packages/backend-rs/src/model/entity/clip_note.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "clip_note")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "ClipNote", use_nullable = true)
-)]
+#[macros::export(object, js_name = "ClipNote")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/drive_file.rs b/packages/backend-rs/src/model/entity/drive_file.rs
index cde8508340..e2139a9a7d 100644
--- a/packages/backend-rs/src/model/entity/drive_file.rs
+++ b/packages/backend-rs/src/model/entity/drive_file.rs
@@ -7,10 +7,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "drive_file")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "DriveFile", use_nullable = true)
-)]
+#[macros::export(object, js_name = "DriveFile")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/drive_folder.rs b/packages/backend-rs/src/model/entity/drive_folder.rs
index 1317e2fc4f..428fc70251 100644
--- a/packages/backend-rs/src/model/entity/drive_folder.rs
+++ b/packages/backend-rs/src/model/entity/drive_folder.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "drive_folder")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "DriveFolder", use_nullable = true)
-)]
+#[macros::export(object, js_name = "DriveFolder")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/emoji.rs b/packages/backend-rs/src/model/entity/emoji.rs
index 5946d99bb5..44744ede08 100644
--- a/packages/backend-rs/src/model/entity/emoji.rs
+++ b/packages/backend-rs/src/model/entity/emoji.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "emoji")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "Emoji", use_nullable = true)
-)]
+#[macros::export(object, js_name = "Emoji")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/follow_request.rs b/packages/backend-rs/src/model/entity/follow_request.rs
index f33f1eef73..f7b6231242 100644
--- a/packages/backend-rs/src/model/entity/follow_request.rs
+++ b/packages/backend-rs/src/model/entity/follow_request.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "follow_request")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "FollowRequest", use_nullable = true)
-)]
+#[macros::export(object, js_name = "FollowRequest")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/following.rs b/packages/backend-rs/src/model/entity/following.rs
index 39f6715df0..3b4459bd9e 100644
--- a/packages/backend-rs/src/model/entity/following.rs
+++ b/packages/backend-rs/src/model/entity/following.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "following")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "Following", use_nullable = true)
-)]
+#[macros::export(object, js_name = "Following")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/gallery_like.rs b/packages/backend-rs/src/model/entity/gallery_like.rs
index 181eb0c497..062854ef29 100644
--- a/packages/backend-rs/src/model/entity/gallery_like.rs
+++ b/packages/backend-rs/src/model/entity/gallery_like.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "gallery_like")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "GalleryLike", use_nullable = true)
-)]
+#[macros::export(object, js_name = "GalleryLike")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/gallery_post.rs b/packages/backend-rs/src/model/entity/gallery_post.rs
index c0b85acf71..3fc93da1ee 100644
--- a/packages/backend-rs/src/model/entity/gallery_post.rs
+++ b/packages/backend-rs/src/model/entity/gallery_post.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "gallery_post")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "GalleryPost", use_nullable = true)
-)]
+#[macros::export(object, js_name = "GalleryPost")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/hashtag.rs b/packages/backend-rs/src/model/entity/hashtag.rs
index 94540b7055..f9bb74b4fe 100644
--- a/packages/backend-rs/src/model/entity/hashtag.rs
+++ b/packages/backend-rs/src/model/entity/hashtag.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "hashtag")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "Hashtag", use_nullable = true)
-)]
+#[macros::export(object, js_name = "Hashtag")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/instance.rs b/packages/backend-rs/src/model/entity/instance.rs
index ab0eb2eeb0..9a49e25ce0 100644
--- a/packages/backend-rs/src/model/entity/instance.rs
+++ b/packages/backend-rs/src/model/entity/instance.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "instance")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "Instance", use_nullable = true)
-)]
+#[macros::export(object, js_name = "Instance")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/messaging_message.rs b/packages/backend-rs/src/model/entity/messaging_message.rs
index 5e38a40da5..202496f012 100644
--- a/packages/backend-rs/src/model/entity/messaging_message.rs
+++ b/packages/backend-rs/src/model/entity/messaging_message.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "messaging_message")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "MessagingMessage", use_nullable = true)
-)]
+#[macros::export(object, js_name = "MessagingMessage")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/meta.rs b/packages/backend-rs/src/model/entity/meta.rs
index dc746c8a1f..023fcef525 100644
--- a/packages/backend-rs/src/model/entity/meta.rs
+++ b/packages/backend-rs/src/model/entity/meta.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "meta")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "Meta", use_nullable = true)
-)]
+#[macros::export(object, js_name = "Meta")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/migrations.rs b/packages/backend-rs/src/model/entity/migrations.rs
index b04a765922..b03aaabc3f 100644
--- a/packages/backend-rs/src/model/entity/migrations.rs
+++ b/packages/backend-rs/src/model/entity/migrations.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "migrations")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "Migrations", use_nullable = true)
-)]
+#[macros::export(object, js_name = "Migrations")]
 pub struct Model {
     #[sea_orm(primary_key)]
     pub id: i32,
diff --git a/packages/backend-rs/src/model/entity/moderation_log.rs b/packages/backend-rs/src/model/entity/moderation_log.rs
index 1e76396b94..2ce71a9c78 100644
--- a/packages/backend-rs/src/model/entity/moderation_log.rs
+++ b/packages/backend-rs/src/model/entity/moderation_log.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "moderation_log")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "ModerationLog", use_nullable = true)
-)]
+#[macros::export(object, js_name = "ModerationLog")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/muted_note.rs b/packages/backend-rs/src/model/entity/muted_note.rs
index 7c600249d6..5e89c2ed2f 100644
--- a/packages/backend-rs/src/model/entity/muted_note.rs
+++ b/packages/backend-rs/src/model/entity/muted_note.rs
@@ -7,10 +7,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "muted_note")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "MutedNote", use_nullable = true)
-)]
+#[macros::export(object, js_name = "MutedNote")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/muting.rs b/packages/backend-rs/src/model/entity/muting.rs
index 6a997a6ce0..eff07c6a17 100644
--- a/packages/backend-rs/src/model/entity/muting.rs
+++ b/packages/backend-rs/src/model/entity/muting.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "muting")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "Muting", use_nullable = true)
-)]
+#[macros::export(object, js_name = "Muting")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/note.rs b/packages/backend-rs/src/model/entity/note.rs
index 22ca46d697..e3bf3c9490 100644
--- a/packages/backend-rs/src/model/entity/note.rs
+++ b/packages/backend-rs/src/model/entity/note.rs
@@ -7,10 +7,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "note")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "Note", use_nullable = true)
-)]
+#[macros::export(object, js_name = "Note")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/note_edit.rs b/packages/backend-rs/src/model/entity/note_edit.rs
index fd14c883d8..66e9a8e5ca 100644
--- a/packages/backend-rs/src/model/entity/note_edit.rs
+++ b/packages/backend-rs/src/model/entity/note_edit.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "note_edit")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "NoteEdit", use_nullable = true)
-)]
+#[macros::export(object, js_name = "NoteEdit")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/note_favorite.rs b/packages/backend-rs/src/model/entity/note_favorite.rs
index 6fa5e1e52a..8db8612109 100644
--- a/packages/backend-rs/src/model/entity/note_favorite.rs
+++ b/packages/backend-rs/src/model/entity/note_favorite.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "note_favorite")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "NoteFavorite", use_nullable = true)
-)]
+#[macros::export(object, js_name = "NoteFavorite")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/note_file.rs b/packages/backend-rs/src/model/entity/note_file.rs
index 812f6d1729..6742bf67aa 100644
--- a/packages/backend-rs/src/model/entity/note_file.rs
+++ b/packages/backend-rs/src/model/entity/note_file.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "note_file")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "NoteFile", use_nullable = true)
-)]
+#[macros::export(object, js_name = "NoteFile")]
 pub struct Model {
     #[sea_orm(column_name = "serialNo", primary_key)]
     pub serial_no: i64,
diff --git a/packages/backend-rs/src/model/entity/note_reaction.rs b/packages/backend-rs/src/model/entity/note_reaction.rs
index 2bfbd00589..e329db8d0f 100644
--- a/packages/backend-rs/src/model/entity/note_reaction.rs
+++ b/packages/backend-rs/src/model/entity/note_reaction.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "note_reaction")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "NoteReaction", use_nullable = true)
-)]
+#[macros::export(object, js_name = "NoteReaction")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/note_thread_muting.rs b/packages/backend-rs/src/model/entity/note_thread_muting.rs
index 7fbb82ddd6..29aa782bd5 100644
--- a/packages/backend-rs/src/model/entity/note_thread_muting.rs
+++ b/packages/backend-rs/src/model/entity/note_thread_muting.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "note_thread_muting")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "NoteThreadMuting", use_nullable = true)
-)]
+#[macros::export(object, js_name = "NoteThreadMuting")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/note_unread.rs b/packages/backend-rs/src/model/entity/note_unread.rs
index bbb3e098a0..da312e6e69 100644
--- a/packages/backend-rs/src/model/entity/note_unread.rs
+++ b/packages/backend-rs/src/model/entity/note_unread.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "note_unread")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "NoteUnread", use_nullable = true)
-)]
+#[macros::export(object, js_name = "NoteUnread")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/note_watching.rs b/packages/backend-rs/src/model/entity/note_watching.rs
index 072cc349a6..5ab675a8e3 100644
--- a/packages/backend-rs/src/model/entity/note_watching.rs
+++ b/packages/backend-rs/src/model/entity/note_watching.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "note_watching")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "NoteWatching", use_nullable = true)
-)]
+#[macros::export(object, js_name = "NoteWatching")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/notification.rs b/packages/backend-rs/src/model/entity/notification.rs
index d259af0021..e73a9cd1fb 100644
--- a/packages/backend-rs/src/model/entity/notification.rs
+++ b/packages/backend-rs/src/model/entity/notification.rs
@@ -7,10 +7,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "notification")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "Notification", use_nullable = true)
-)]
+#[macros::export(object, js_name = "Notification")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/page.rs b/packages/backend-rs/src/model/entity/page.rs
index 909e0618a6..f252a43532 100644
--- a/packages/backend-rs/src/model/entity/page.rs
+++ b/packages/backend-rs/src/model/entity/page.rs
@@ -7,10 +7,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "page")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "Page", use_nullable = true)
-)]
+#[macros::export(object, js_name = "Page")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/page_like.rs b/packages/backend-rs/src/model/entity/page_like.rs
index 6c3bafbbc7..d6aa22c12a 100644
--- a/packages/backend-rs/src/model/entity/page_like.rs
+++ b/packages/backend-rs/src/model/entity/page_like.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "page_like")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "PageLike", use_nullable = true)
-)]
+#[macros::export(object, js_name = "PageLike")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/password_reset_request.rs b/packages/backend-rs/src/model/entity/password_reset_request.rs
index 3e1a69abf7..bd4978a44c 100644
--- a/packages/backend-rs/src/model/entity/password_reset_request.rs
+++ b/packages/backend-rs/src/model/entity/password_reset_request.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "password_reset_request")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "PasswordResetRequest", use_nullable = true)
-)]
+#[macros::export(object, js_name = "PasswordResetRequest")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/poll.rs b/packages/backend-rs/src/model/entity/poll.rs
index 16d1c043db..501243252f 100644
--- a/packages/backend-rs/src/model/entity/poll.rs
+++ b/packages/backend-rs/src/model/entity/poll.rs
@@ -7,10 +7,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "poll")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "Poll", use_nullable = true)
-)]
+#[macros::export(object, js_name = "Poll")]
 pub struct Model {
     #[sea_orm(column_name = "noteId", primary_key, auto_increment = false, unique)]
     pub note_id: String,
diff --git a/packages/backend-rs/src/model/entity/poll_vote.rs b/packages/backend-rs/src/model/entity/poll_vote.rs
index 04eebba773..f3a84d2cdf 100644
--- a/packages/backend-rs/src/model/entity/poll_vote.rs
+++ b/packages/backend-rs/src/model/entity/poll_vote.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "poll_vote")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "PollVote", use_nullable = true)
-)]
+#[macros::export(object, js_name = "PollVote")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/promo_note.rs b/packages/backend-rs/src/model/entity/promo_note.rs
index c1321922b0..24b1b98651 100644
--- a/packages/backend-rs/src/model/entity/promo_note.rs
+++ b/packages/backend-rs/src/model/entity/promo_note.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "promo_note")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "PromoNote", use_nullable = true)
-)]
+#[macros::export(object, js_name = "PromoNote")]
 pub struct Model {
     #[sea_orm(column_name = "noteId", primary_key, auto_increment = false, unique)]
     pub note_id: String,
diff --git a/packages/backend-rs/src/model/entity/promo_read.rs b/packages/backend-rs/src/model/entity/promo_read.rs
index 3df163fd72..097b6e3cc4 100644
--- a/packages/backend-rs/src/model/entity/promo_read.rs
+++ b/packages/backend-rs/src/model/entity/promo_read.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "promo_read")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "PromoRead", use_nullable = true)
-)]
+#[macros::export(object, js_name = "PromoRead")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/registration_ticket.rs b/packages/backend-rs/src/model/entity/registration_ticket.rs
index ad5138f614..7a25c016b8 100644
--- a/packages/backend-rs/src/model/entity/registration_ticket.rs
+++ b/packages/backend-rs/src/model/entity/registration_ticket.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "registration_ticket")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "RegistrationTicket", use_nullable = true)
-)]
+#[macros::export(object, js_name = "RegistrationTicket")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/registry_item.rs b/packages/backend-rs/src/model/entity/registry_item.rs
index 9b6b4ca5bc..7dbc5e37b9 100644
--- a/packages/backend-rs/src/model/entity/registry_item.rs
+++ b/packages/backend-rs/src/model/entity/registry_item.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "registry_item")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "RegistryItem", use_nullable = true)
-)]
+#[macros::export(object, js_name = "RegistryItem")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/relay.rs b/packages/backend-rs/src/model/entity/relay.rs
index eb3b3bf952..6648179f87 100644
--- a/packages/backend-rs/src/model/entity/relay.rs
+++ b/packages/backend-rs/src/model/entity/relay.rs
@@ -7,10 +7,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "relay")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "Relay", use_nullable = true)
-)]
+#[macros::export(object, js_name = "Relay")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/renote_muting.rs b/packages/backend-rs/src/model/entity/renote_muting.rs
index 99b08d5a9d..1adc965f16 100644
--- a/packages/backend-rs/src/model/entity/renote_muting.rs
+++ b/packages/backend-rs/src/model/entity/renote_muting.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "renote_muting")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "RenoteMuting", use_nullable = true)
-)]
+#[macros::export(object, js_name = "RenoteMuting")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/reply_muting.rs b/packages/backend-rs/src/model/entity/reply_muting.rs
index 7e3b61cdca..5f01f223df 100644
--- a/packages/backend-rs/src/model/entity/reply_muting.rs
+++ b/packages/backend-rs/src/model/entity/reply_muting.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "reply_muting")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "ReplyMuting", use_nullable = true)
-)]
+#[macros::export(object, js_name = "ReplyMuting")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/sea_orm_active_enums.rs b/packages/backend-rs/src/model/entity/sea_orm_active_enums.rs
index bd1582cb61..5515dad01e 100644
--- a/packages/backend-rs/src/model/entity/sea_orm_active_enums.rs
+++ b/packages/backend-rs/src/model/entity/sea_orm_active_enums.rs
@@ -5,8 +5,7 @@ use serde::{Deserialize, Serialize};
 
 #[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
-#[cfg_attr(not(feature = "napi"), derive(Clone))]
-#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
+#[macros::derive_clone_and_export(string_enum = "camelCase")]
 #[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "antenna_src")]
 pub enum AntennaSrc {
     #[sea_orm(string_value = "all")]
@@ -24,8 +23,7 @@ pub enum AntennaSrc {
 }
 #[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
-#[cfg_attr(not(feature = "napi"), derive(Clone))]
-#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
+#[macros::derive_clone_and_export(string_enum = "camelCase")]
 #[sea_orm(
     rs_type = "String",
     db_type = "Enum",
@@ -39,8 +37,7 @@ pub enum DriveFileUsageHint {
 }
 #[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
-#[cfg_attr(not(feature = "napi"), derive(Clone))]
-#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
+#[macros::derive_clone_and_export(string_enum = "camelCase")]
 #[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "muted_note_reason")]
 pub enum MutedNoteReason {
     #[sea_orm(string_value = "manual")]
@@ -54,8 +51,7 @@ pub enum MutedNoteReason {
 }
 #[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
-#[cfg_attr(not(feature = "napi"), derive(Clone))]
-#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
+#[macros::derive_clone_and_export(string_enum = "camelCase")]
 #[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "note_visibility")]
 pub enum NoteVisibility {
     #[sea_orm(string_value = "followers")]
@@ -71,8 +67,7 @@ pub enum NoteVisibility {
 }
 #[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
-#[cfg_attr(not(feature = "napi"), derive(Clone))]
-#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
+#[macros::derive_clone_and_export(string_enum = "camelCase")]
 #[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "notification_type")]
 pub enum NotificationType {
     #[sea_orm(string_value = "app")]
@@ -102,8 +97,7 @@ pub enum NotificationType {
 }
 #[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
-#[cfg_attr(not(feature = "napi"), derive(Clone))]
-#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
+#[macros::derive_clone_and_export(string_enum = "camelCase")]
 #[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "page_visibility")]
 pub enum PageVisibility {
     #[sea_orm(string_value = "followers")]
@@ -115,8 +109,7 @@ pub enum PageVisibility {
 }
 #[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
-#[cfg_attr(not(feature = "napi"), derive(Clone))]
-#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
+#[macros::derive_clone_and_export(string_enum = "camelCase")]
 #[sea_orm(
     rs_type = "String",
     db_type = "Enum",
@@ -134,8 +127,7 @@ pub enum PollNoteVisibility {
 }
 #[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
-#[cfg_attr(not(feature = "napi"), derive(Clone))]
-#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
+#[macros::derive_clone_and_export(string_enum = "camelCase")]
 #[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "relay_status")]
 pub enum RelayStatus {
     #[sea_orm(string_value = "accepted")]
@@ -147,8 +139,7 @@ pub enum RelayStatus {
 }
 #[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
-#[cfg_attr(not(feature = "napi"), derive(Clone))]
-#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
+#[macros::derive_clone_and_export(string_enum = "camelCase")]
 #[sea_orm(
     rs_type = "String",
     db_type = "Enum",
@@ -166,8 +157,7 @@ pub enum UserEmojiModPerm {
 }
 #[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
-#[cfg_attr(not(feature = "napi"), derive(Clone))]
-#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
+#[macros::derive_clone_and_export(string_enum = "camelCase")]
 #[sea_orm(
     rs_type = "String",
     db_type = "Enum",
@@ -183,8 +173,7 @@ pub enum UserProfileFfvisibility {
 }
 #[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
-#[cfg_attr(not(feature = "napi"), derive(Clone))]
-#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
+#[macros::derive_clone_and_export(string_enum = "camelCase")]
 #[sea_orm(
     rs_type = "String",
     db_type = "Enum",
diff --git a/packages/backend-rs/src/model/entity/signin.rs b/packages/backend-rs/src/model/entity/signin.rs
index 914f1d068b..aec9f2dfe6 100644
--- a/packages/backend-rs/src/model/entity/signin.rs
+++ b/packages/backend-rs/src/model/entity/signin.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "signin")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "Signin", use_nullable = true)
-)]
+#[macros::export(object, js_name = "Signin")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/sw_subscription.rs b/packages/backend-rs/src/model/entity/sw_subscription.rs
index 6a2751f93f..5273587e0c 100644
--- a/packages/backend-rs/src/model/entity/sw_subscription.rs
+++ b/packages/backend-rs/src/model/entity/sw_subscription.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "sw_subscription")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "SwSubscription", use_nullable = true)
-)]
+#[macros::export(object, js_name = "SwSubscription")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/used_username.rs b/packages/backend-rs/src/model/entity/used_username.rs
index 30998043ae..84e55baba7 100644
--- a/packages/backend-rs/src/model/entity/used_username.rs
+++ b/packages/backend-rs/src/model/entity/used_username.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "used_username")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "UsedUsername", use_nullable = true)
-)]
+#[macros::export(object, js_name = "UsedUsername")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub username: String,
diff --git a/packages/backend-rs/src/model/entity/user.rs b/packages/backend-rs/src/model/entity/user.rs
index 196db137ff..f11e1e43d9 100644
--- a/packages/backend-rs/src/model/entity/user.rs
+++ b/packages/backend-rs/src/model/entity/user.rs
@@ -7,10 +7,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "user")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "User", use_nullable = true)
-)]
+#[macros::export(object, js_name = "User")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/user_group.rs b/packages/backend-rs/src/model/entity/user_group.rs
index c49ff625e4..f035750e4b 100644
--- a/packages/backend-rs/src/model/entity/user_group.rs
+++ b/packages/backend-rs/src/model/entity/user_group.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "user_group")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "UserGroup", use_nullable = true)
-)]
+#[macros::export(object, js_name = "UserGroup")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/user_group_invitation.rs b/packages/backend-rs/src/model/entity/user_group_invitation.rs
index 7f74649c01..41073b38fc 100644
--- a/packages/backend-rs/src/model/entity/user_group_invitation.rs
+++ b/packages/backend-rs/src/model/entity/user_group_invitation.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "user_group_invitation")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "UserGroupInvitation", use_nullable = true)
-)]
+#[macros::export(object, js_name = "UserGroupInvitation")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/user_group_invite.rs b/packages/backend-rs/src/model/entity/user_group_invite.rs
index e3333cf46a..28c831155c 100644
--- a/packages/backend-rs/src/model/entity/user_group_invite.rs
+++ b/packages/backend-rs/src/model/entity/user_group_invite.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "user_group_invite")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "UserGroupInvite", use_nullable = true)
-)]
+#[macros::export(object, js_name = "UserGroupInvite")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/user_group_joining.rs b/packages/backend-rs/src/model/entity/user_group_joining.rs
index be94fa9306..99f38d1856 100644
--- a/packages/backend-rs/src/model/entity/user_group_joining.rs
+++ b/packages/backend-rs/src/model/entity/user_group_joining.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "user_group_joining")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "UserGroupJoining", use_nullable = true)
-)]
+#[macros::export(object, js_name = "UserGroupJoining")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/user_ip.rs b/packages/backend-rs/src/model/entity/user_ip.rs
index 724bd024cb..326d82b74a 100644
--- a/packages/backend-rs/src/model/entity/user_ip.rs
+++ b/packages/backend-rs/src/model/entity/user_ip.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "user_ip")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "UserIp", use_nullable = true)
-)]
+#[macros::export(object, js_name = "UserIp")]
 pub struct Model {
     #[sea_orm(primary_key)]
     pub id: i32,
diff --git a/packages/backend-rs/src/model/entity/user_keypair.rs b/packages/backend-rs/src/model/entity/user_keypair.rs
index 791390ca21..cbc203e6ec 100644
--- a/packages/backend-rs/src/model/entity/user_keypair.rs
+++ b/packages/backend-rs/src/model/entity/user_keypair.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "user_keypair")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "UserKeypair", use_nullable = true)
-)]
+#[macros::export(object, js_name = "UserKeypair")]
 pub struct Model {
     #[sea_orm(column_name = "userId", primary_key, auto_increment = false, unique)]
     pub user_id: String,
diff --git a/packages/backend-rs/src/model/entity/user_list.rs b/packages/backend-rs/src/model/entity/user_list.rs
index d498c43cb3..839eab1c02 100644
--- a/packages/backend-rs/src/model/entity/user_list.rs
+++ b/packages/backend-rs/src/model/entity/user_list.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "user_list")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "UserList", use_nullable = true)
-)]
+#[macros::export(object, js_name = "UserList")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/user_list_joining.rs b/packages/backend-rs/src/model/entity/user_list_joining.rs
index bafec1114e..3158cbad21 100644
--- a/packages/backend-rs/src/model/entity/user_list_joining.rs
+++ b/packages/backend-rs/src/model/entity/user_list_joining.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "user_list_joining")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "UserListJoining", use_nullable = true)
-)]
+#[macros::export(object, js_name = "UserListJoining")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/user_note_pining.rs b/packages/backend-rs/src/model/entity/user_note_pining.rs
index 2eefd74ee8..2a4c4e83e2 100644
--- a/packages/backend-rs/src/model/entity/user_note_pining.rs
+++ b/packages/backend-rs/src/model/entity/user_note_pining.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "user_note_pining")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "UserNotePining", use_nullable = true)
-)]
+#[macros::export(object, js_name = "UserNotePining")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/user_pending.rs b/packages/backend-rs/src/model/entity/user_pending.rs
index 8b5dfd367c..6c0265bc2f 100644
--- a/packages/backend-rs/src/model/entity/user_pending.rs
+++ b/packages/backend-rs/src/model/entity/user_pending.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "user_pending")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "UserPending", use_nullable = true)
-)]
+#[macros::export(object, js_name = "UserPending")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/user_profile.rs b/packages/backend-rs/src/model/entity/user_profile.rs
index 56c6d8ed7b..1c55a1a604 100644
--- a/packages/backend-rs/src/model/entity/user_profile.rs
+++ b/packages/backend-rs/src/model/entity/user_profile.rs
@@ -8,10 +8,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "user_profile")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "UserProfile", use_nullable = true)
-)]
+#[macros::export(object, js_name = "UserProfile")]
 pub struct Model {
     #[sea_orm(column_name = "userId", primary_key, auto_increment = false, unique)]
     pub user_id: String,
diff --git a/packages/backend-rs/src/model/entity/user_publickey.rs b/packages/backend-rs/src/model/entity/user_publickey.rs
index 676d652b97..a0605e9d2e 100644
--- a/packages/backend-rs/src/model/entity/user_publickey.rs
+++ b/packages/backend-rs/src/model/entity/user_publickey.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "user_publickey")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "UserPublickey", use_nullable = true)
-)]
+#[macros::export(object, js_name = "UserPublickey")]
 pub struct Model {
     #[sea_orm(column_name = "userId", primary_key, auto_increment = false, unique)]
     pub user_id: String,
diff --git a/packages/backend-rs/src/model/entity/user_security_key.rs b/packages/backend-rs/src/model/entity/user_security_key.rs
index f5ac43ed3b..fdc61638a3 100644
--- a/packages/backend-rs/src/model/entity/user_security_key.rs
+++ b/packages/backend-rs/src/model/entity/user_security_key.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "user_security_key")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "UserSecurityKey", use_nullable = true)
-)]
+#[macros::export(object, js_name = "UserSecurityKey")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,
diff --git a/packages/backend-rs/src/model/entity/webhook.rs b/packages/backend-rs/src/model/entity/webhook.rs
index baed1d02f4..b2695bee62 100644
--- a/packages/backend-rs/src/model/entity/webhook.rs
+++ b/packages/backend-rs/src/model/entity/webhook.rs
@@ -6,10 +6,7 @@ use serde::{Deserialize, Serialize};
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[sea_orm(table_name = "webhook")]
-#[cfg_attr(
-    feature = "napi",
-    napi_derive::napi(object, js_name = "Webhook", use_nullable = true)
-)]
+#[macros::export(object, js_name = "Webhook")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     pub id: String,