Merge branch 'develop' into iceshrimp_mastodon
This commit is contained in:
commit
f6643325c0
74 changed files with 1216 additions and 1003 deletions
|
@ -289,7 +289,7 @@ cargo:doc:
|
|||
- cp ci/cargo/config.toml /usr/local/cargo/config.toml
|
||||
script:
|
||||
- cargo doc --document-private-items
|
||||
- printf "window.ALL_CRATES = ['backend_rs', 'macro_rs'];" > target/doc/crates.js
|
||||
- printf 'window.ALL_CRATES = ["backend_rs", "macros", "macros_impl"];' > target/doc/crates.js
|
||||
- printf '<meta http-equiv="refresh" content="0; url=%s">' 'backend_rs' > target/doc/index.html
|
||||
- cd target/doc
|
||||
- npx --yes netlify-cli deploy --prod --site="${CARGO_DOC_SITE_ID}" --dir=.
|
||||
|
|
18
Cargo.lock
generated
18
Cargo.lock
generated
|
@ -210,7 +210,7 @@ dependencies = [
|
|||
"idna",
|
||||
"image",
|
||||
"isahc",
|
||||
"macro-rs",
|
||||
"macros",
|
||||
"napi",
|
||||
"napi-build",
|
||||
"napi-derive",
|
||||
|
@ -1718,18 +1718,24 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "macro-rs"
|
||||
name = "macros"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"convert_case",
|
||||
"napi",
|
||||
"napi-derive",
|
||||
"macros-impl",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "macros-impl"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"convert_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.66",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
[workspace]
|
||||
members = ["packages/backend-rs", "packages/macro-rs"]
|
||||
members = ["packages/backend-rs", "packages/macro-rs/macros", "packages/macro-rs/macros-impl"]
|
||||
resolver = "2"
|
||||
|
||||
[workspace.dependencies]
|
||||
macro-rs = { path = "packages/macro-rs" }
|
||||
macros = { path = "packages/macro-rs/macros" }
|
||||
macros-impl = { path = "packages/macro-rs/macros-impl" }
|
||||
|
||||
napi = { git = "https://github.com/napi-rs/napi-rs.git", rev = "ca2cd5c35a0c39ec4a94e93c6c5695b681046df2" }
|
||||
napi-derive = "2.16.5"
|
||||
|
|
19
Dockerfile
19
Dockerfile
|
@ -2,23 +2,23 @@
|
|||
FROM docker.io/node:20-alpine as build
|
||||
WORKDIR /firefish
|
||||
|
||||
# Copy only backend-rs pnpm-related files first, to cache efficiently
|
||||
COPY package.json pnpm-workspace.yaml ./
|
||||
COPY packages/backend-rs/package.json packages/backend-rs/package.json
|
||||
COPY packages/backend-rs/npm/linux-x64-musl/package.json packages/backend-rs/npm/linux-x64-musl/package.json
|
||||
COPY packages/backend-rs/npm/linux-arm64-musl/package.json packages/backend-rs/npm/linux-arm64-musl/package.json
|
||||
|
||||
# Install compilation dependencies
|
||||
RUN apk update && apk add --no-cache build-base linux-headers curl ca-certificates python3 perl
|
||||
RUN curl --proto '=https' --tlsv1.2 --silent --show-error --fail https://sh.rustup.rs | sh -s -- -y
|
||||
ENV PATH="/root/.cargo/bin:${PATH}"
|
||||
|
||||
# Copy only backend-rs dependency-related files first, to cache efficiently
|
||||
COPY package.json pnpm-workspace.yaml ./
|
||||
COPY packages/backend-rs/package.json packages/backend-rs/package.json
|
||||
COPY packages/backend-rs/npm/linux-x64-musl/package.json packages/backend-rs/npm/linux-x64-musl/package.json
|
||||
COPY packages/backend-rs/npm/linux-arm64-musl/package.json packages/backend-rs/npm/linux-arm64-musl/package.json
|
||||
|
||||
COPY packages/macro-rs packages/macro-rs/
|
||||
COPY packages/backend-rs/src/lib.rs packages/backend-rs/src/
|
||||
COPY packages/backend-rs/Cargo.toml packages/backend-rs/Cargo.toml
|
||||
COPY Cargo.toml Cargo.toml
|
||||
COPY Cargo.lock Cargo.lock
|
||||
COPY packages/backend-rs/Cargo.toml packages/backend-rs/Cargo.toml
|
||||
COPY packages/backend-rs/src/lib.rs packages/backend-rs/src/
|
||||
COPY packages/macro-rs/Cargo.toml packages/macro-rs/Cargo.toml
|
||||
COPY packages/macro-rs/src/lib.rs packages/macro-rs/src/
|
||||
|
||||
# Configure pnpm, and install backend-rs dependencies
|
||||
RUN corepack enable && corepack prepare pnpm@latest --activate && pnpm --filter backend-rs install
|
||||
|
@ -26,7 +26,6 @@ RUN cargo fetch --locked --manifest-path Cargo.toml
|
|||
|
||||
# Copy in the rest of the rust files
|
||||
COPY packages/backend-rs packages/backend-rs/
|
||||
# COPY packages/macro-rs packages/macro-rs/
|
||||
|
||||
# Compile backend-rs
|
||||
RUN NODE_ENV='production' pnpm run --filter backend-rs build
|
||||
|
|
|
@ -12,7 +12,7 @@ napi = ["dep:napi", "dep:napi-derive", "dep:napi-build"]
|
|||
crate-type = ["cdylib", "lib"]
|
||||
|
||||
[dependencies]
|
||||
macro-rs = { workspace = true }
|
||||
macros = { workspace = true }
|
||||
|
||||
napi = { workspace = true, optional = true, features = ["chrono_date", "napi4", "serde-json", "tokio_rt"] }
|
||||
napi-derive = { workspace = true, optional = true }
|
||||
|
|
13
packages/backend-rs/index.d.ts
vendored
13
packages/backend-rs/index.d.ts
vendored
|
@ -1393,6 +1393,18 @@ export interface PackedEmoji {
|
|||
height: number | null
|
||||
}
|
||||
export function publishToBroadcastStream(emoji: PackedEmoji): Promise<void>
|
||||
export enum DriveFileEvent {
|
||||
Create = 0,
|
||||
Update = 1,
|
||||
Delete = 2
|
||||
}
|
||||
export enum DriveFolderEvent {
|
||||
Create = 0,
|
||||
Update = 1,
|
||||
Delete = 2
|
||||
}
|
||||
export function publishToDriveFileStream(userId: string, kind: DriveFileEvent, object: any): Promise<void>
|
||||
export function publishToDriveFolderStream(userId: string, kind: DriveFolderEvent, object: any): Promise<void>
|
||||
export function publishToGroupChatStream(groupId: string, kind: ChatEvent, object: any): Promise<void>
|
||||
export interface AbuseUserReportLike {
|
||||
id: string
|
||||
|
@ -1401,6 +1413,7 @@ export interface AbuseUserReportLike {
|
|||
comment: string
|
||||
}
|
||||
export function publishToModerationStream(moderatorId: string, report: AbuseUserReportLike): Promise<void>
|
||||
export function publishToNotesStream(note: Note): Promise<void>
|
||||
export enum ChatEvent {
|
||||
Message = 0,
|
||||
Read = 1,
|
||||
|
|
|
@ -310,7 +310,7 @@ if (!nativeBinding) {
|
|||
throw new Error(`Failed to load native binding`)
|
||||
}
|
||||
|
||||
const { SECOND, MINUTE, HOUR, DAY, USER_ONLINE_THRESHOLD, USER_ACTIVE_THRESHOLD, FILE_TYPE_BROWSERSAFE, fetchMeta, updateMetaCache, metaToPugArgs, loadConfig, stringToAcct, acctToString, fetchNodeinfo, nodeinfo_2_1, nodeinfo_2_0, updateNodeinfoCache, Protocol, Inbound, Outbound, greet, initializeRustLogger, showServerInfo, isBlockedServer, isSilencedServer, isAllowedServer, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, isUnicodeEmoji, sqlLikeEscape, sqlRegexEscape, safeForSql, formatMilliseconds, getImageSizeFromUrl, isQuote, isSafeUrl, latestVersion, getNoteSummary, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, decodeReaction, countReactions, toDbReaction, removeOldAttestationChallenges, cpuInfo, cpuUsage, memoryUsage, storageUsage, AntennaSrc, DriveFileUsageHint, MutedNoteReason, NoteVisibility, NotificationType, PageVisibility, PollNoteVisibility, PushSubscriptionType, RelayStatus, UserEmojiModPerm, UserProfileFfvisibility, UserProfileMutingNotificationTypes, updateAntennasOnNewNote, updateAntennaCache, watchNote, unwatchNote, PushNotificationKind, sendPushNotification, publishToChannelStream, publishToChatStream, ChatIndexEvent, publishToChatIndexStream, publishToBroadcastStream, publishToGroupChatStream, publishToModerationStream, ChatEvent, getTimestamp, genId, genIdAt, generateSecureRandomString, generateUserToken } = nativeBinding
|
||||
const { SECOND, MINUTE, HOUR, DAY, USER_ONLINE_THRESHOLD, USER_ACTIVE_THRESHOLD, FILE_TYPE_BROWSERSAFE, fetchMeta, updateMetaCache, metaToPugArgs, loadConfig, stringToAcct, acctToString, fetchNodeinfo, nodeinfo_2_1, nodeinfo_2_0, updateNodeinfoCache, Protocol, Inbound, Outbound, greet, initializeRustLogger, showServerInfo, isBlockedServer, isSilencedServer, isAllowedServer, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, isUnicodeEmoji, sqlLikeEscape, sqlRegexEscape, safeForSql, formatMilliseconds, getImageSizeFromUrl, isQuote, isSafeUrl, latestVersion, getNoteSummary, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, decodeReaction, countReactions, toDbReaction, removeOldAttestationChallenges, cpuInfo, cpuUsage, memoryUsage, storageUsage, AntennaSrc, DriveFileUsageHint, MutedNoteReason, NoteVisibility, NotificationType, PageVisibility, PollNoteVisibility, PushSubscriptionType, RelayStatus, UserEmojiModPerm, UserProfileFfvisibility, UserProfileMutingNotificationTypes, updateAntennasOnNewNote, updateAntennaCache, watchNote, unwatchNote, PushNotificationKind, sendPushNotification, publishToChannelStream, publishToChatStream, ChatIndexEvent, publishToChatIndexStream, publishToBroadcastStream, DriveFileEvent, DriveFolderEvent, publishToDriveFileStream, publishToDriveFolderStream, publishToGroupChatStream, publishToModerationStream, publishToNotesStream, ChatEvent, getTimestamp, genId, genIdAt, generateSecureRandomString, generateUserToken } = nativeBinding
|
||||
|
||||
module.exports.SECOND = SECOND
|
||||
module.exports.MINUTE = MINUTE
|
||||
|
@ -389,8 +389,13 @@ module.exports.publishToChatStream = publishToChatStream
|
|||
module.exports.ChatIndexEvent = ChatIndexEvent
|
||||
module.exports.publishToChatIndexStream = publishToChatIndexStream
|
||||
module.exports.publishToBroadcastStream = publishToBroadcastStream
|
||||
module.exports.DriveFileEvent = DriveFileEvent
|
||||
module.exports.DriveFolderEvent = DriveFolderEvent
|
||||
module.exports.publishToDriveFileStream = publishToDriveFileStream
|
||||
module.exports.publishToDriveFolderStream = publishToDriveFolderStream
|
||||
module.exports.publishToGroupChatStream = publishToGroupChatStream
|
||||
module.exports.publishToModerationStream = publishToModerationStream
|
||||
module.exports.publishToNotesStream = publishToNotesStream
|
||||
module.exports.ChatEvent = ChatEvent
|
||||
module.exports.getTimestamp = getTimestamp
|
||||
module.exports.genId = genId
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
//! This module is used in the TypeScript backend only.
|
||||
|
||||
#[crate::ts_export]
|
||||
#[macros::ts_export]
|
||||
pub const SECOND: i32 = 1000;
|
||||
#[crate::ts_export]
|
||||
#[macros::ts_export]
|
||||
pub const MINUTE: i32 = 60 * SECOND;
|
||||
#[crate::ts_export]
|
||||
#[macros::ts_export]
|
||||
pub const HOUR: i32 = 60 * MINUTE;
|
||||
#[crate::ts_export]
|
||||
#[macros::ts_export]
|
||||
pub const DAY: i32 = 24 * HOUR;
|
||||
|
||||
#[crate::ts_export]
|
||||
#[macros::ts_export]
|
||||
pub const USER_ONLINE_THRESHOLD: i32 = 10 * MINUTE;
|
||||
#[crate::ts_export]
|
||||
#[macros::ts_export]
|
||||
pub const USER_ACTIVE_THRESHOLD: i32 = 3 * DAY;
|
||||
|
||||
/// List of file types allowed to be viewed directly in the browser
|
||||
|
@ -21,7 +21,7 @@ pub const USER_ACTIVE_THRESHOLD: i32 = 3 * DAY;
|
|||
/// * <https://github.com/sindresorhus/file-type/blob/main/supported.js>
|
||||
/// * <https://github.com/sindresorhus/file-type/blob/main/core.js>
|
||||
/// * <https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Containers>
|
||||
#[crate::ts_export]
|
||||
#[macros::ts_export]
|
||||
pub const FILE_TYPE_BROWSERSAFE: [&str; 41] = [
|
||||
// Images
|
||||
"image/png",
|
||||
|
|
|
@ -11,12 +11,12 @@ fn set_cache(meta: &Meta) {
|
|||
let _ = CACHE.lock().map(|mut cache| *cache = Some(meta.clone()));
|
||||
}
|
||||
|
||||
#[crate::export(js_name = "fetchMeta")]
|
||||
#[macros::export(js_name = "fetchMeta")]
|
||||
pub async fn local_server_info() -> Result<Meta, DbErr> {
|
||||
local_server_info_impl(true).await
|
||||
}
|
||||
|
||||
#[crate::export(js_name = "updateMetaCache")]
|
||||
#[macros::export(js_name = "updateMetaCache")]
|
||||
pub async fn update() -> Result<(), DbErr> {
|
||||
local_server_info_impl(false).await?;
|
||||
Ok(())
|
||||
|
@ -49,7 +49,7 @@ async fn local_server_info_impl(use_cache: bool) -> Result<Meta, DbErr> {
|
|||
Ok(meta)
|
||||
}
|
||||
|
||||
#[crate::export(object)]
|
||||
#[macros::export(object)]
|
||||
pub struct PugArgs {
|
||||
pub img: Option<String>,
|
||||
pub title: String,
|
||||
|
@ -62,7 +62,7 @@ pub struct PugArgs {
|
|||
pub private_mode: Option<bool>,
|
||||
}
|
||||
|
||||
#[crate::ts_export]
|
||||
#[macros::ts_export]
|
||||
pub fn meta_to_pug_args(meta: Meta) -> PugArgs {
|
||||
use rand::prelude::*;
|
||||
let mut rng = rand::thread_rng();
|
||||
|
|
|
@ -4,11 +4,11 @@ use once_cell::sync::Lazy;
|
|||
use serde::Deserialize;
|
||||
use std::{env, fs};
|
||||
|
||||
pub const VERSION: &str = macro_rs::read_version_from_package_json!();
|
||||
pub const VERSION: &str = macros::read_version_from_package_json!();
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[crate::export(object, use_nullable = false)]
|
||||
#[macros::export(object, use_nullable = false)]
|
||||
struct ServerConfig {
|
||||
pub url: String,
|
||||
pub port: u16,
|
||||
|
@ -73,7 +73,7 @@ struct ServerConfig {
|
|||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[crate::export(object, use_nullable = false)]
|
||||
#[macros::export(object, use_nullable = false)]
|
||||
pub struct DbConfig {
|
||||
pub host: String,
|
||||
pub port: u16,
|
||||
|
@ -86,7 +86,7 @@ pub struct DbConfig {
|
|||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[crate::export(object, use_nullable = false)]
|
||||
#[macros::export(object, use_nullable = false)]
|
||||
pub struct RedisConfig {
|
||||
pub host: String,
|
||||
pub port: u16,
|
||||
|
@ -101,13 +101,13 @@ pub struct RedisConfig {
|
|||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[crate::export(object, use_nullable = false)]
|
||||
#[macros::export(object, use_nullable = false)]
|
||||
pub struct TlsConfig {
|
||||
pub host: String,
|
||||
pub reject_unauthorized: bool,
|
||||
}
|
||||
|
||||
#[crate::export(object, use_nullable = false)]
|
||||
#[macros::export(object, use_nullable = false)]
|
||||
pub struct WorkerConfig {
|
||||
pub web: u32,
|
||||
pub queue: u32,
|
||||
|
@ -115,7 +115,7 @@ pub struct WorkerConfig {
|
|||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[crate::export(object, use_nullable = false)]
|
||||
#[macros::export(object, use_nullable = false)]
|
||||
pub struct WorkerConfigInternal {
|
||||
pub web: Option<u32>,
|
||||
pub queue: Option<u32>,
|
||||
|
@ -123,7 +123,7 @@ pub struct WorkerConfigInternal {
|
|||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[crate::export(object, use_nullable = false)]
|
||||
#[macros::export(object, use_nullable = false)]
|
||||
pub struct IdConfig {
|
||||
pub length: Option<u8>,
|
||||
pub fingerprint: Option<String>,
|
||||
|
@ -131,7 +131,7 @@ pub struct IdConfig {
|
|||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[crate::export(object, use_nullable = false)]
|
||||
#[macros::export(object, use_nullable = false)]
|
||||
pub struct SysLogConfig {
|
||||
pub host: String,
|
||||
pub port: u16,
|
||||
|
@ -139,7 +139,7 @@ pub struct SysLogConfig {
|
|||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[crate::export(object, use_nullable = false)]
|
||||
#[macros::export(object, use_nullable = false)]
|
||||
pub struct DeepLConfig {
|
||||
pub managed: Option<bool>,
|
||||
pub auth_key: Option<String>,
|
||||
|
@ -148,7 +148,7 @@ pub struct DeepLConfig {
|
|||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[crate::export(object, use_nullable = false)]
|
||||
#[macros::export(object, use_nullable = false)]
|
||||
pub struct LibreTranslateConfig {
|
||||
pub managed: Option<bool>,
|
||||
pub api_url: Option<String>,
|
||||
|
@ -157,7 +157,7 @@ pub struct LibreTranslateConfig {
|
|||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[crate::export(object, use_nullable = false)]
|
||||
#[macros::export(object, use_nullable = false)]
|
||||
pub struct EmailConfig {
|
||||
pub managed: Option<bool>,
|
||||
pub address: Option<String>,
|
||||
|
@ -170,7 +170,7 @@ pub struct EmailConfig {
|
|||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[crate::export(object, use_nullable = false)]
|
||||
#[macros::export(object, use_nullable = false)]
|
||||
pub struct ObjectStorageConfig {
|
||||
pub managed: Option<bool>,
|
||||
pub base_url: Option<String>,
|
||||
|
@ -186,7 +186,7 @@ pub struct ObjectStorageConfig {
|
|||
pub s3_force_path_style: Option<bool>,
|
||||
}
|
||||
|
||||
#[crate::export(object, use_nullable = false)]
|
||||
#[macros::export(object, use_nullable = false)]
|
||||
pub struct Config {
|
||||
// ServerConfig (from default.yml)
|
||||
pub url: String,
|
||||
|
@ -263,7 +263,7 @@ fn read_config_file() -> ServerConfig {
|
|||
data
|
||||
}
|
||||
|
||||
#[crate::export]
|
||||
#[macros::export]
|
||||
pub fn load_config() -> Config {
|
||||
let server_config = read_config_file();
|
||||
let version = VERSION.to_owned();
|
||||
|
|
|
@ -234,6 +234,7 @@ mod unit_test {
|
|||
use pretty_assertions::assert_eq;
|
||||
|
||||
#[tokio::test]
|
||||
#[cfg_attr(miri, ignore)] // can't call foreign function `getaddrinfo` on OS `linux`
|
||||
async fn set_get_expire() {
|
||||
#[derive(serde::Deserialize, serde::Serialize, PartialEq, Debug)]
|
||||
struct Data {
|
||||
|
@ -278,6 +279,7 @@ mod unit_test {
|
|||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[cfg_attr(miri, ignore)] // can't call foreign function `getaddrinfo` on OS `linux`
|
||||
async fn use_category() {
|
||||
let key_1 = "fire";
|
||||
let key_2 = "fish";
|
||||
|
|
|
@ -42,6 +42,7 @@ mod unit_test {
|
|||
use sea_orm::{prelude::*, DbBackend, Statement};
|
||||
|
||||
#[tokio::test]
|
||||
#[cfg_attr(miri, ignore)] // can't call foreign function `geteuid` on OS `linux`
|
||||
async fn connect_sequential() {
|
||||
get_conn().await.unwrap();
|
||||
get_conn().await.unwrap();
|
||||
|
@ -51,12 +52,14 @@ mod unit_test {
|
|||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[cfg_attr(miri, ignore)] // can't call foreign function `geteuid` on OS `linux`
|
||||
async fn connect_concurrent() {
|
||||
let [c1, c2, c3, c4, c5] = [get_conn(), get_conn(), get_conn(), get_conn(), get_conn()];
|
||||
let _ = tokio::try_join!(c1, c2, c3, c4, c5).unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[cfg_attr(miri, ignore)] // can't call foreign function `geteuid` on OS `linux`
|
||||
async fn connect_spawn() {
|
||||
let mut tasks = Vec::new();
|
||||
|
||||
|
@ -69,6 +72,7 @@ mod unit_test {
|
|||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[cfg_attr(miri, ignore)] // can't call foreign function `geteuid` on OS `linux`
|
||||
async fn access() {
|
||||
// DO NOT write any raw SQL query in the actual program
|
||||
// (with the exception of PGroonga features)
|
||||
|
|
|
@ -119,6 +119,7 @@ mod unit_test {
|
|||
use redis::AsyncCommands;
|
||||
|
||||
#[tokio::test]
|
||||
#[cfg_attr(miri, ignore)] // can't call foreign function `getaddrinfo` on OS `linux`
|
||||
async fn connect_sequential() {
|
||||
get_conn().await.unwrap();
|
||||
get_conn().await.unwrap();
|
||||
|
@ -128,12 +129,14 @@ mod unit_test {
|
|||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[cfg_attr(miri, ignore)] // can't call foreign function `getaddrinfo` on OS `linux`
|
||||
async fn connect_concurrent() {
|
||||
let [c1, c2, c3, c4, c5] = [get_conn(), get_conn(), get_conn(), get_conn(), get_conn()];
|
||||
let _ = tokio::try_join!(c1, c2, c3, c4, c5).unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[cfg_attr(miri, ignore)] // can't call foreign function `getaddrinfo` on OS `linux`
|
||||
async fn connect_spawn() {
|
||||
let mut tasks = Vec::new();
|
||||
|
||||
|
@ -146,6 +149,7 @@ mod unit_test {
|
|||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[cfg_attr(miri, ignore)] // can't call foreign function `getaddrinfo` on OS `linux`
|
||||
async fn access() {
|
||||
let mut redis = get_conn().await.unwrap();
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::{fmt, str::FromStr};
|
||||
|
||||
#[cfg_attr(test, derive(Debug, PartialEq))]
|
||||
#[crate::export(object)]
|
||||
#[macros::export(object)]
|
||||
pub struct Acct {
|
||||
pub username: String,
|
||||
pub host: Option<String>,
|
||||
|
@ -51,12 +51,12 @@ impl From<Acct> for String {
|
|||
}
|
||||
}
|
||||
|
||||
#[crate::ts_export]
|
||||
#[macros::ts_export]
|
||||
pub fn string_to_acct(acct: &str) -> Acct {
|
||||
Acct::from_str(acct).unwrap()
|
||||
}
|
||||
|
||||
#[crate::ts_export]
|
||||
#[macros::ts_export]
|
||||
pub fn acct_to_string(acct: &Acct) -> String {
|
||||
acct.to_string()
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ async fn fetch_nodeinfo_impl(nodeinfo_link: &str) -> Result<Nodeinfo20, Error> {
|
|||
type Nodeinfo = Nodeinfo20;
|
||||
|
||||
/// Fetches and returns the NodeInfo (version 2.0) of a remote server.
|
||||
#[crate::export]
|
||||
#[macros::export]
|
||||
pub async fn fetch_nodeinfo(host: &str) -> Result<Nodeinfo, Error> {
|
||||
tracing::info!("fetching from {}", host);
|
||||
let links = fetch_nodeinfo_links(host).await?;
|
||||
|
@ -156,6 +156,7 @@ mod unit_test {
|
|||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[cfg_attr(miri, ignore)] // can't call foreign function `curl_global_init` on OS `linux`
|
||||
async fn fetch_nodeinfo() {
|
||||
assert_eq!(
|
||||
super::fetch_nodeinfo("info.firefish.dev")
|
||||
|
|
|
@ -161,17 +161,17 @@ pub enum Error {
|
|||
Json(#[from] serde_json::Error),
|
||||
}
|
||||
|
||||
#[crate::ts_export(js_name = "nodeinfo_2_1")]
|
||||
#[macros::ts_export(js_name = "nodeinfo_2_1")]
|
||||
pub async fn nodeinfo_2_1_as_json() -> Result<serde_json::Value, Error> {
|
||||
Ok(serde_json::to_value(nodeinfo_2_1().await?)?)
|
||||
}
|
||||
|
||||
#[crate::ts_export(js_name = "nodeinfo_2_0")]
|
||||
#[macros::ts_export(js_name = "nodeinfo_2_0")]
|
||||
pub async fn nodeinfo_2_0_as_json() -> Result<serde_json::Value, Error> {
|
||||
Ok(serde_json::to_value(nodeinfo_2_0().await?)?)
|
||||
}
|
||||
|
||||
#[crate::ts_export(js_name = "updateNodeinfoCache")]
|
||||
#[macros::ts_export(js_name = "updateNodeinfoCache")]
|
||||
pub async fn update_cache() -> Result<(), DbErr> {
|
||||
nodeinfo_2_1_impl(false).await?;
|
||||
Ok(())
|
||||
|
|
|
@ -34,7 +34,7 @@ pub struct Nodeinfo21 {
|
|||
#[cfg_attr(test, derive(Debug, PartialEq))]
|
||||
#[derive(Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[crate::export(object, js_name = "Nodeinfo")]
|
||||
#[macros::export(object, js_name = "Nodeinfo")]
|
||||
pub struct Nodeinfo20 {
|
||||
/// The schema version, must be 2.0.
|
||||
pub version: String,
|
||||
|
@ -71,7 +71,7 @@ pub struct Software21 {
|
|||
#[cfg_attr(test, derive(Debug, PartialEq))]
|
||||
#[derive(Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[crate::export(object)]
|
||||
#[macros::export(object)]
|
||||
pub struct Software20 {
|
||||
/// The canonical name of this server software.
|
||||
pub name: String,
|
||||
|
@ -82,7 +82,7 @@ pub struct Software20 {
|
|||
#[cfg_attr(test, derive(Debug, PartialEq))]
|
||||
#[derive(Deserialize, Serialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
#[crate::derive_clone_and_export]
|
||||
#[macros::derive_clone_and_export]
|
||||
pub enum Protocol {
|
||||
Activitypub,
|
||||
Buddycloud,
|
||||
|
@ -100,7 +100,7 @@ pub enum Protocol {
|
|||
#[cfg_attr(test, derive(Debug, PartialEq))]
|
||||
#[derive(Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[crate::export(object)]
|
||||
#[macros::export(object)]
|
||||
pub struct Services {
|
||||
/// The third party sites this server can retrieve messages from for combined display with regular traffic.
|
||||
pub inbound: Vec<Inbound>,
|
||||
|
@ -112,7 +112,7 @@ pub struct Services {
|
|||
#[cfg_attr(test, derive(Debug, PartialEq))]
|
||||
#[derive(Deserialize, Serialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
#[crate::derive_clone_and_export]
|
||||
#[macros::derive_clone_and_export]
|
||||
pub enum Inbound {
|
||||
#[serde(rename = "atom1.0")]
|
||||
Atom1,
|
||||
|
@ -131,7 +131,7 @@ pub enum Inbound {
|
|||
#[cfg_attr(test, derive(Debug, PartialEq))]
|
||||
#[derive(Deserialize, Serialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
#[crate::derive_clone_and_export]
|
||||
#[macros::derive_clone_and_export]
|
||||
pub enum Outbound {
|
||||
#[serde(rename = "atom1.0")]
|
||||
Atom1,
|
||||
|
@ -169,7 +169,7 @@ pub enum Outbound {
|
|||
#[cfg_attr(test, derive(Debug, PartialEq))]
|
||||
#[derive(Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[crate::export(object)]
|
||||
#[macros::export(object)]
|
||||
pub struct Usage {
|
||||
pub users: Users,
|
||||
pub local_posts: Option<u32>,
|
||||
|
@ -180,7 +180,7 @@ pub struct Usage {
|
|||
#[cfg_attr(test, derive(Debug, PartialEq))]
|
||||
#[derive(Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[crate::export(object)]
|
||||
#[macros::export(object)]
|
||||
pub struct Users {
|
||||
pub total: Option<u32>,
|
||||
pub active_halfyear: Option<u32>,
|
||||
|
|
|
@ -12,7 +12,7 @@ const GREETING_MESSAGE: &str = "\
|
|||
";
|
||||
|
||||
/// Prints the greeting message and the Firefish version to stdout.
|
||||
#[crate::export]
|
||||
#[macros::export]
|
||||
pub fn greet() {
|
||||
println!("{}", GREETING_MESSAGE);
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ use tracing::Level;
|
|||
use tracing_subscriber::FmtSubscriber;
|
||||
|
||||
/// Initializes the [tracing] logger.
|
||||
#[crate::export(js_name = "initializeRustLogger")]
|
||||
#[macros::export(js_name = "initializeRustLogger")]
|
||||
pub fn initialize_logger() {
|
||||
let mut builder = FmtSubscriber::builder();
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ pub fn system_info() -> &'static std::sync::Mutex<System> {
|
|||
}
|
||||
|
||||
/// Prints the server hardware information as the server info log.
|
||||
#[crate::export]
|
||||
#[macros::export]
|
||||
pub fn show_server_info() -> Result<(), SysinfoPoisonError> {
|
||||
let system_info = system_info().lock()?;
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
use macro_rs::{derive_clone_and_export, export, ts_export};
|
||||
|
||||
pub mod config;
|
||||
pub mod database;
|
||||
pub mod federation;
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[crate::ts_export]
|
||||
#[macros::ts_export]
|
||||
pub async fn is_blocked_server(host: &str) -> Result<bool, sea_orm::DbErr> {
|
||||
Ok(crate::config::local_server_info()
|
||||
.await?
|
||||
|
@ -45,7 +45,7 @@ pub async fn is_blocked_server(host: &str) -> Result<bool, sea_orm::DbErr> {
|
|||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[crate::ts_export]
|
||||
#[macros::ts_export]
|
||||
pub async fn is_silenced_server(host: &str) -> Result<bool, sea_orm::DbErr> {
|
||||
Ok(crate::config::local_server_info()
|
||||
.await?
|
||||
|
@ -73,7 +73,7 @@ pub async fn is_silenced_server(host: &str) -> Result<bool, sea_orm::DbErr> {
|
|||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[crate::ts_export]
|
||||
#[macros::ts_export]
|
||||
pub async fn is_allowed_server(host: &str) -> Result<bool, sea_orm::DbErr> {
|
||||
let meta = crate::config::local_server_info().await?;
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ use once_cell::sync::Lazy;
|
|||
use regex::Regex;
|
||||
use sea_orm::DbErr;
|
||||
|
||||
#[crate::export(object)]
|
||||
#[macros::export(object)]
|
||||
pub struct PartialNoteToCheckWordMute {
|
||||
pub file_ids: Vec<String>,
|
||||
pub text: Option<String>,
|
||||
|
@ -49,7 +49,7 @@ fn check_word_mute_impl(
|
|||
/// * `note` : [PartialNoteToCheckWordMute] object
|
||||
/// * `muted_words` : list of muted keyword lists (each array item is a space-separated keyword list that represents an AND condition)
|
||||
/// * `muted_patterns` : list of JavaScript-style (e.g., `/foo/i`) regular expressions
|
||||
#[crate::export]
|
||||
#[macros::export]
|
||||
pub async fn check_word_mute(
|
||||
note: PartialNoteToCheckWordMute,
|
||||
muted_words: &[String],
|
||||
|
|
|
@ -13,7 +13,7 @@ pub enum Error {
|
|||
NoHostname,
|
||||
}
|
||||
|
||||
#[crate::ts_export]
|
||||
#[macros::ts_export]
|
||||
pub fn get_full_ap_account(username: &str, host: Option<&str>) -> Result<String, Error> {
|
||||
Ok(match host {
|
||||
Some(host) => format!("{}@{}", username, to_puny(host)?),
|
||||
|
@ -21,7 +21,7 @@ pub fn get_full_ap_account(username: &str, host: Option<&str>) -> Result<String,
|
|||
})
|
||||
}
|
||||
|
||||
#[crate::ts_export]
|
||||
#[macros::ts_export]
|
||||
pub fn is_self_host(host: Option<&str>) -> Result<bool, Error> {
|
||||
Ok(match host {
|
||||
Some(host) => extract_host(&crate::config::CONFIG.url)? == to_puny(host)?,
|
||||
|
@ -29,12 +29,12 @@ pub fn is_self_host(host: Option<&str>) -> Result<bool, Error> {
|
|||
})
|
||||
}
|
||||
|
||||
#[crate::ts_export]
|
||||
#[macros::ts_export]
|
||||
pub fn is_same_origin(uri: &str) -> Result<bool, Error> {
|
||||
Ok(url::Url::parse(uri)?.origin().ascii_serialization() == crate::config::CONFIG.url)
|
||||
}
|
||||
|
||||
#[crate::ts_export]
|
||||
#[macros::ts_export]
|
||||
pub fn extract_host(uri: &str) -> Result<String, Error> {
|
||||
url::Url::parse(uri)?
|
||||
.host_str()
|
||||
|
@ -42,7 +42,7 @@ pub fn extract_host(uri: &str) -> Result<String, Error> {
|
|||
.and_then(|v| Ok(to_puny(v)?))
|
||||
}
|
||||
|
||||
#[crate::ts_export]
|
||||
#[macros::ts_export]
|
||||
pub fn to_puny(host: &str) -> Result<String, idna::Errors> {
|
||||
idna::domain_to_ascii(host)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//! This module is used in the TypeScript backend only.
|
||||
|
||||
#[crate::ts_export]
|
||||
#[macros::ts_export]
|
||||
pub fn is_unicode_emoji(s: &str) -> bool {
|
||||
emojis::get(s).is_some()
|
||||
}
|
||||
|
|
|
@ -2,19 +2,19 @@ use once_cell::sync::Lazy;
|
|||
use regex::Regex;
|
||||
|
||||
/// Escapes `%` and `\` in the given string.
|
||||
#[crate::export]
|
||||
#[macros::export]
|
||||
pub fn sql_like_escape(src: &str) -> String {
|
||||
src.replace('%', r"\%").replace('_', r"\_")
|
||||
}
|
||||
|
||||
#[crate::export]
|
||||
#[macros::export]
|
||||
pub fn sql_regex_escape(src: &str) -> String {
|
||||
static RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"[!$()*+.:<=>?\[\]\^{|}-]").unwrap());
|
||||
RE.replace_all(src, r"\$1").to_string()
|
||||
}
|
||||
|
||||
/// Returns `true` if `src` does not contain suspicious characters like `%`.
|
||||
#[crate::export]
|
||||
#[macros::export]
|
||||
pub fn safe_for_sql(src: &str) -> bool {
|
||||
!src.contains([
|
||||
'\0', '\x08', '\x09', '\x1a', '\n', '\r', '"', '\'', '\\', '%',
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/// Converts milliseconds to a human readable string.
|
||||
#[crate::export]
|
||||
#[macros::export]
|
||||
pub fn format_milliseconds(milliseconds: u32) -> String {
|
||||
let mut seconds = milliseconds / 1000;
|
||||
let mut minutes = seconds / 60;
|
||||
|
|
|
@ -44,13 +44,13 @@ const BROWSER_SAFE_IMAGE_TYPES: [ImageFormat; 8] = [
|
|||
static MTX_GUARD: Mutex<()> = Mutex::const_new(());
|
||||
|
||||
#[cfg_attr(test, derive(Debug, PartialEq))]
|
||||
#[crate::export(object)]
|
||||
#[macros::export(object)]
|
||||
pub struct ImageSize {
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
}
|
||||
|
||||
#[crate::export]
|
||||
#[macros::export]
|
||||
pub async fn get_image_size_from_url(url: &str) -> Result<ImageSize, Error> {
|
||||
let attempted: bool;
|
||||
|
||||
|
@ -134,6 +134,7 @@ mod unit_test {
|
|||
use pretty_assertions::assert_eq;
|
||||
|
||||
#[tokio::test]
|
||||
#[cfg_attr(miri, ignore)] // can't call foreign function `getaddrinfo` on OS `linux`
|
||||
async fn get_image_size_from_url() {
|
||||
let png_url_1 = "https://firefish.dev/firefish/firefish/-/raw/5891a90f71a8b9d5ea99c683ade7e485c685d642/packages/backend/assets/splash.png";
|
||||
let png_url_2 = "https://firefish.dev/firefish/firefish/-/raw/5891a90f71a8b9d5ea99c683ade7e485c685d642/packages/backend/assets/notification-badges/at.png";
|
||||
|
@ -219,6 +220,7 @@ mod unit_test {
|
|||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[cfg_attr(miri, ignore)] // can't call foreign function `getaddrinfo` on OS `linux`
|
||||
async fn too_many_attempts() {
|
||||
let url = "https://firefish.dev/firefish/firefish/-/raw/5891a90f71a8b9d5ea99c683ade7e485c685d642/packages/backend/assets/splash.png";
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// TODO?: handle name collisions
|
||||
#[crate::export(object, js_name = "NoteLikeForIsQuote")]
|
||||
#[macros::export(object, js_name = "NoteLikeForIsQuote")]
|
||||
pub struct NoteLike {
|
||||
pub renote_id: Option<String>,
|
||||
pub text: Option<String>,
|
||||
|
@ -7,7 +7,7 @@ pub struct NoteLike {
|
|||
pub file_ids: Vec<String>,
|
||||
}
|
||||
|
||||
#[crate::export]
|
||||
#[macros::export]
|
||||
pub fn is_quote(note: &NoteLike) -> bool {
|
||||
note.renote_id.is_some() && (note.text.is_some() || note.has_poll || !note.file_ids.is_empty())
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#[crate::export]
|
||||
#[macros::export]
|
||||
pub fn is_safe_url(url: &str) -> bool {
|
||||
if let Ok(url) = url.parse::<url::Url>() {
|
||||
if url.host_str().unwrap_or_default() == "unix"
|
||||
|
|
|
@ -46,7 +46,7 @@ async fn get_latest_version() -> Result<String, Error> {
|
|||
}
|
||||
|
||||
/// Returns the latest Firefish version.
|
||||
#[crate::export]
|
||||
#[macros::export]
|
||||
pub async fn latest_version() -> Result<String, Error> {
|
||||
let version: Option<String> =
|
||||
cache::get_one(cache::Category::FetchUrl, UPSTREAM_PACKAGE_JSON_URL).await?;
|
||||
|
@ -99,6 +99,7 @@ mod unit_test {
|
|||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[cfg_attr(miri, ignore)] // can't call foreign function `getaddrinfo` on OS `linux`
|
||||
async fn get_latest_version() {
|
||||
// delete caches in case you run this test multiple times
|
||||
cache::delete_one(cache::Category::FetchUrl, UPSTREAM_PACKAGE_JSON_URL)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#[crate::export(js_name = "getNoteSummary")]
|
||||
#[macros::export(js_name = "getNoteSummary")]
|
||||
pub fn summarize_impl(
|
||||
file_ids: &[String],
|
||||
text: Option<String>,
|
||||
|
|
|
@ -20,7 +20,7 @@ use regex::{Captures, Regex};
|
|||
/// # use backend_rs::misc::nyaify::nyaify;
|
||||
/// assert_eq!(nyaify("I'll take a nap.", Some("en")), "I'll take a nyap.");
|
||||
/// ```
|
||||
#[crate::export]
|
||||
#[macros::export]
|
||||
pub fn nyaify(text: &str, lang: Option<&str>) -> String {
|
||||
let mut to_return = text.to_owned();
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ use argon2::{
|
|||
};
|
||||
|
||||
/// Hashes the given password using [argon2] algorithm.
|
||||
#[crate::export]
|
||||
#[macros::export]
|
||||
pub fn hash_password(password: &str) -> Result<String, password_hash::errors::Error> {
|
||||
let salt = SaltString::generate(&mut OsRng);
|
||||
Ok(Argon2::default()
|
||||
|
@ -26,7 +26,7 @@ pub enum Error {
|
|||
}
|
||||
|
||||
/// Checks whether the given password and hash match.
|
||||
#[crate::export]
|
||||
#[macros::export]
|
||||
pub fn verify_password(password: &str, hash: &str) -> Result<bool, Error> {
|
||||
if is_old_password_algorithm(hash) {
|
||||
Ok(bcrypt::verify(password, hash)?)
|
||||
|
@ -40,7 +40,7 @@ pub fn verify_password(password: &str, hash: &str) -> Result<bool, Error> {
|
|||
|
||||
/// Returns whether the [bcrypt] algorithm is used for the password hash.
|
||||
#[inline]
|
||||
#[crate::export]
|
||||
#[macros::export]
|
||||
pub fn is_old_password_algorithm(hash: &str) -> bool {
|
||||
// bcrypt hashes start with $2[ab]$
|
||||
hash.starts_with("$2")
|
||||
|
@ -51,6 +51,7 @@ mod unit_test {
|
|||
use super::{hash_password, is_old_password_algorithm};
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(miri, ignore)] // too slow
|
||||
fn verify_password() {
|
||||
let password = "omWc*%sD^fn7o2cXmc9e2QasBdrbRuhNB*gx!J5";
|
||||
|
||||
|
|
|
@ -5,14 +5,14 @@ use sea_orm::prelude::*;
|
|||
use std::collections::HashMap;
|
||||
|
||||
#[cfg_attr(test, derive(PartialEq, Debug))]
|
||||
#[crate::export(object)]
|
||||
#[macros::export(object)]
|
||||
pub struct DecodedReaction {
|
||||
pub reaction: String,
|
||||
pub name: Option<String>,
|
||||
pub host: Option<String>,
|
||||
}
|
||||
|
||||
#[crate::export]
|
||||
#[macros::export]
|
||||
pub fn decode_reaction(reaction: &str) -> DecodedReaction {
|
||||
// Misskey allows you to include "+" and "-" in emoji shortcodes
|
||||
// MFM spec: https://github.com/misskey-dev/mfm.js/blob/6aaf68089023c6adebe44123eebbc4dcd75955e0/docs/syntax.md?plain=1#L583
|
||||
|
@ -38,7 +38,7 @@ pub fn decode_reaction(reaction: &str) -> DecodedReaction {
|
|||
}
|
||||
}
|
||||
|
||||
#[crate::export]
|
||||
#[macros::export]
|
||||
pub fn count_reactions(reactions: &HashMap<String, u32>) -> HashMap<String, u32> {
|
||||
let mut res = HashMap::<String, u32>::new();
|
||||
|
||||
|
@ -62,7 +62,7 @@ pub enum Error {
|
|||
Db(#[from] DbErr),
|
||||
}
|
||||
|
||||
#[crate::export]
|
||||
#[macros::export]
|
||||
pub async fn to_db_reaction(reaction: Option<&str>, host: Option<&str>) -> Result<String, Error> {
|
||||
if let Some(reaction) = reaction {
|
||||
// FIXME: Is it okay to do this only here?
|
||||
|
|
|
@ -5,7 +5,7 @@ use chrono::{Duration, Utc};
|
|||
use sea_orm::prelude::*;
|
||||
|
||||
/// Delete all entries in the [attestation_challenge] table created at more than 5 minutes ago
|
||||
#[crate::export]
|
||||
#[macros::export]
|
||||
pub async fn remove_old_attestation_challenges() -> Result<(), DbErr> {
|
||||
let res = attestation_challenge::Entity::delete_many()
|
||||
.filter(attestation_challenge::Column::CreatedAt.lt(Utc::now() - Duration::minutes(5)))
|
||||
|
|
|
@ -5,14 +5,14 @@ use sysinfo::{Disks, MemoryRefreshKind};
|
|||
|
||||
// TODO: i64 -> u64 (we can't export u64 to Node.js)
|
||||
|
||||
#[crate::export(object)]
|
||||
#[macros::export(object)]
|
||||
pub struct Cpu {
|
||||
pub model: String,
|
||||
// TODO: u16 -> usize (we can't export usize to Node.js)
|
||||
pub cores: u16,
|
||||
}
|
||||
|
||||
#[crate::export(object)]
|
||||
#[macros::export(object)]
|
||||
pub struct Memory {
|
||||
/// Total memory amount in bytes
|
||||
pub total: i64,
|
||||
|
@ -22,7 +22,7 @@ pub struct Memory {
|
|||
pub available: i64,
|
||||
}
|
||||
|
||||
#[crate::export(object)]
|
||||
#[macros::export(object)]
|
||||
pub struct Storage {
|
||||
/// Total storage space in bytes
|
||||
pub total: i64,
|
||||
|
@ -30,7 +30,7 @@ pub struct Storage {
|
|||
pub used: i64,
|
||||
}
|
||||
|
||||
#[crate::export]
|
||||
#[macros::export]
|
||||
pub fn cpu_info() -> Result<Cpu, SysinfoPoisonError> {
|
||||
let system_info = system_info().lock()?;
|
||||
|
||||
|
@ -46,7 +46,7 @@ pub fn cpu_info() -> Result<Cpu, SysinfoPoisonError> {
|
|||
})
|
||||
}
|
||||
|
||||
#[crate::export]
|
||||
#[macros::export]
|
||||
pub fn cpu_usage() -> Result<f32, SysinfoPoisonError> {
|
||||
let mut system_info = system_info().lock()?;
|
||||
system_info.refresh_cpu_usage();
|
||||
|
@ -57,7 +57,7 @@ pub fn cpu_usage() -> Result<f32, SysinfoPoisonError> {
|
|||
Ok(total_cpu_usage / (cpu_threads as f32))
|
||||
}
|
||||
|
||||
#[crate::export]
|
||||
#[macros::export]
|
||||
pub fn memory_usage() -> Result<Memory, SysinfoPoisonError> {
|
||||
let mut system_info = system_info().lock()?;
|
||||
|
||||
|
@ -70,7 +70,7 @@ pub fn memory_usage() -> Result<Memory, SysinfoPoisonError> {
|
|||
})
|
||||
}
|
||||
|
||||
#[crate::export]
|
||||
#[macros::export]
|
||||
pub fn storage_usage() -> Option<Storage> {
|
||||
// Get the first disk that is actualy used (has available space & has at least 1 GB total space).
|
||||
let disks = Disks::new_with_refreshed_list();
|
||||
|
|
|
@ -37,7 +37,7 @@ pub enum Error {
|
|||
// https://github.com/napi-rs/napi-rs/issues/2060
|
||||
type Note = note::Model;
|
||||
|
||||
#[crate::export]
|
||||
#[macros::export]
|
||||
pub async fn update_antennas_on_new_note(
|
||||
note: &Note,
|
||||
note_author: &Acct,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//! This module is (currently) used in the TypeScript backend only.
|
||||
|
||||
#[crate::ts_export]
|
||||
#[macros::ts_export]
|
||||
pub async fn update_antenna_cache() -> Result<(), sea_orm::DbErr> {
|
||||
super::cache::update().await?;
|
||||
Ok(())
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::{database::db_conn, model::entity::note_watching, util::id::gen_id_at};
|
||||
use sea_orm::{prelude::*, ActiveValue};
|
||||
|
||||
#[crate::export]
|
||||
#[macros::export]
|
||||
pub async fn watch_note(
|
||||
watcher_id: &str,
|
||||
note_author_id: &str,
|
||||
|
@ -24,7 +24,7 @@ pub async fn watch_note(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[crate::export]
|
||||
#[macros::export]
|
||||
pub async fn unwatch_note(watcher_id: &str, note_id: &str) -> Result<(), DbErr> {
|
||||
let db = db_conn().await?;
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ fn get_client() -> Result<IsahcWebPushClient, Error> {
|
|||
.cloned()?)
|
||||
}
|
||||
|
||||
#[crate::export]
|
||||
#[macros::export]
|
||||
pub enum PushNotificationKind {
|
||||
Generic,
|
||||
Chat,
|
||||
|
@ -243,7 +243,7 @@ async fn handle_web_push_failure(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[crate::export]
|
||||
#[macros::export]
|
||||
pub async fn send_push_notification(
|
||||
receiver_user_id: &str,
|
||||
kind: PushNotificationKind,
|
||||
|
|
|
@ -3,8 +3,10 @@ pub mod channel;
|
|||
pub mod chat;
|
||||
pub mod chat_index;
|
||||
pub mod custom_emoji;
|
||||
pub mod drive;
|
||||
pub mod group_chat;
|
||||
pub mod moderation;
|
||||
pub mod notes;
|
||||
|
||||
use crate::{
|
||||
config::CONFIG,
|
||||
|
@ -52,7 +54,7 @@ pub enum Stream {
|
|||
},
|
||||
}
|
||||
|
||||
#[crate::export]
|
||||
#[macros::export]
|
||||
pub enum ChatEvent {
|
||||
Message,
|
||||
Read,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::service::stream::{publish_to_stream, Error, Stream};
|
||||
|
||||
#[crate::export(js_name = "publishToChannelStream")]
|
||||
#[macros::export(js_name = "publishToChannelStream")]
|
||||
pub async fn publish(channel_id: String, user_id: String) -> Result<(), Error> {
|
||||
publish_to_stream(
|
||||
&Stream::Channel { channel_id },
|
||||
|
|
|
@ -3,7 +3,7 @@ use crate::service::stream::{publish_to_stream, ChatEvent, Error, Stream};
|
|||
// We want to merge `kind` and `object` into a single enum
|
||||
// https://github.com/napi-rs/napi-rs/issues/2036
|
||||
|
||||
#[crate::export(js_name = "publishToChatStream")]
|
||||
#[macros::export(js_name = "publishToChatStream")]
|
||||
pub async fn publish(
|
||||
sender_user_id: String,
|
||||
receiver_user_id: String,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::service::stream::{publish_to_stream, Error, Stream};
|
||||
|
||||
#[crate::export]
|
||||
#[macros::export]
|
||||
pub enum ChatIndexEvent {
|
||||
Message,
|
||||
Read,
|
||||
|
@ -9,7 +9,7 @@ pub enum ChatIndexEvent {
|
|||
// We want to merge `kind` and `object` into a single enum
|
||||
// https://github.com/napi-rs/napi-rs/issues/2036
|
||||
|
||||
#[crate::export(js_name = "publishToChatIndexStream")]
|
||||
#[macros::export(js_name = "publishToChatIndexStream")]
|
||||
pub async fn publish(
|
||||
user_id: String,
|
||||
kind: ChatIndexEvent,
|
||||
|
|
|
@ -4,7 +4,7 @@ use serde::Serialize;
|
|||
// TODO: define schema type in other place
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[crate::export(object)]
|
||||
#[macros::export(object)]
|
||||
pub struct PackedEmoji {
|
||||
pub id: String,
|
||||
pub aliases: Vec<String>,
|
||||
|
@ -17,7 +17,7 @@ pub struct PackedEmoji {
|
|||
pub height: Option<i32>,
|
||||
}
|
||||
|
||||
#[crate::export(js_name = "publishToBroadcastStream")]
|
||||
#[macros::export(js_name = "publishToBroadcastStream")]
|
||||
pub async fn publish(emoji: &PackedEmoji) -> Result<(), Error> {
|
||||
publish_to_stream(
|
||||
&Stream::CustomEmoji,
|
||||
|
|
58
packages/backend-rs/src/service/stream/drive.rs
Normal file
58
packages/backend-rs/src/service/stream/drive.rs
Normal file
|
@ -0,0 +1,58 @@
|
|||
use crate::service::stream::{publish_to_stream, Error, Stream};
|
||||
|
||||
#[macros::export]
|
||||
pub enum DriveFileEvent {
|
||||
Create,
|
||||
Update,
|
||||
Delete,
|
||||
}
|
||||
|
||||
#[macros::export]
|
||||
pub enum DriveFolderEvent {
|
||||
Create,
|
||||
Update,
|
||||
Delete,
|
||||
}
|
||||
|
||||
// We want to merge `kind` and `object` into a single enum and merge the 2 functions
|
||||
// https://github.com/napi-rs/napi-rs/issues/2036
|
||||
|
||||
#[macros::export(js_name = "publishToDriveFileStream")]
|
||||
pub async fn publish_file(
|
||||
user_id: String,
|
||||
kind: DriveFileEvent,
|
||||
object: &serde_json::Value, // file (create, update) or file id (delete)
|
||||
) -> Result<(), Error> {
|
||||
let kind = match kind {
|
||||
DriveFileEvent::Create => "fileCreated",
|
||||
DriveFileEvent::Update => "fileUpdated",
|
||||
DriveFileEvent::Delete => "fileDeleted",
|
||||
};
|
||||
|
||||
publish_to_stream(
|
||||
&Stream::Drive { user_id },
|
||||
Some(kind),
|
||||
Some(serde_json::to_string(object)?),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
#[macros::export(js_name = "publishToDriveFolderStream")]
|
||||
pub async fn publish_folder(
|
||||
user_id: String,
|
||||
kind: DriveFolderEvent,
|
||||
object: &serde_json::Value, // folder (create, update) or folder id (delete)
|
||||
) -> Result<(), Error> {
|
||||
let kind = match kind {
|
||||
DriveFolderEvent::Create => "folderCreated",
|
||||
DriveFolderEvent::Update => "folderUpdated",
|
||||
DriveFolderEvent::Delete => "folderDeleted",
|
||||
};
|
||||
|
||||
publish_to_stream(
|
||||
&Stream::Drive { user_id },
|
||||
Some(kind),
|
||||
Some(serde_json::to_string(object)?),
|
||||
)
|
||||
.await
|
||||
}
|
|
@ -3,7 +3,7 @@ use crate::service::stream::{publish_to_stream, ChatEvent, Error, Stream};
|
|||
// We want to merge `kind` and `object` into a single enum
|
||||
// https://github.com/napi-rs/napi-rs/issues/2036
|
||||
|
||||
#[crate::export(js_name = "publishToGroupChatStream")]
|
||||
#[macros::export(js_name = "publishToGroupChatStream")]
|
||||
pub async fn publish(
|
||||
group_id: String,
|
||||
kind: ChatEvent,
|
||||
|
|
|
@ -3,7 +3,7 @@ use serde::Serialize;
|
|||
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[crate::export(object)]
|
||||
#[macros::export(object)]
|
||||
pub struct AbuseUserReportLike {
|
||||
pub id: String,
|
||||
pub target_user_id: String,
|
||||
|
@ -11,7 +11,7 @@ pub struct AbuseUserReportLike {
|
|||
pub comment: String,
|
||||
}
|
||||
|
||||
#[crate::export(js_name = "publishToModerationStream")]
|
||||
#[macros::export(js_name = "publishToModerationStream")]
|
||||
pub async fn publish(moderator_id: String, report: &AbuseUserReportLike) -> Result<(), Error> {
|
||||
publish_to_stream(
|
||||
&Stream::Moderation { moderator_id },
|
||||
|
|
13
packages/backend-rs/src/service/stream/notes.rs
Normal file
13
packages/backend-rs/src/service/stream/notes.rs
Normal file
|
@ -0,0 +1,13 @@
|
|||
use crate::{
|
||||
model::entity::note,
|
||||
service::stream::{publish_to_stream, Error, Stream},
|
||||
};
|
||||
|
||||
// for napi export
|
||||
// https://github.com/napi-rs/napi-rs/issues/2060
|
||||
type Note = note::Model;
|
||||
|
||||
#[macros::export(js_name = "publishToNotesStream")]
|
||||
pub async fn publish(note: &Note) -> Result<(), Error> {
|
||||
publish_to_stream(&Stream::Notes, None, Some(serde_json::to_string(note)?)).await
|
||||
}
|
|
@ -70,21 +70,13 @@ mod unit_test {
|
|||
let expected_message_1 = "
|
||||
raw: Error1(InnerError1)
|
||||
message: error 1 occured
|
||||
caused by: inner error 1
|
||||
";
|
||||
caused by: inner error 1";
|
||||
let expected_message_2 = r#"
|
||||
raw: Error2(InnerError2("foo"))
|
||||
message: error 2 occured
|
||||
caused by: unexpected string 'foo'
|
||||
"#;
|
||||
caused by: unexpected string 'foo'"#;
|
||||
|
||||
assert_eq!(
|
||||
error_message_1,
|
||||
expected_message_1[1..expected_message_1.len() - 1]
|
||||
);
|
||||
assert_eq!(
|
||||
error_message_2,
|
||||
expected_message_2[1..expected_message_2.len() - 1]
|
||||
);
|
||||
assert_eq!(error_message_1, expected_message_1[1..]);
|
||||
assert_eq!(error_message_2, expected_message_2[1..]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ pub struct InvalidIdError {
|
|||
id: String,
|
||||
}
|
||||
|
||||
#[crate::export]
|
||||
#[macros::export]
|
||||
pub fn get_timestamp(id: &str) -> Result<i64, InvalidIdError> {
|
||||
let n: Option<u64> = BASE36.decode_var_len(&id[0..8]);
|
||||
if let Some(n) = n {
|
||||
|
@ -68,13 +68,13 @@ pub fn get_timestamp(id: &str) -> Result<i64, InvalidIdError> {
|
|||
/// in the same millisecond to reach 50% chance of collision.
|
||||
///
|
||||
/// Ref: <https://github.com/paralleldrive/cuid2#parameterized-length>
|
||||
#[crate::export]
|
||||
#[macros::export]
|
||||
pub fn gen_id() -> String {
|
||||
create_id(&Utc::now().naive_utc())
|
||||
}
|
||||
|
||||
/// Generate an ID using a specific datetime
|
||||
#[crate::export]
|
||||
#[macros::export]
|
||||
pub fn gen_id_at(date: DateTime<Utc>) -> String {
|
||||
create_id(&date.naive_utc())
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
use rand::{distributions::Alphanumeric, thread_rng, Rng};
|
||||
|
||||
/// Generates a random string based on [thread_rng] and [Alphanumeric].
|
||||
#[crate::export]
|
||||
#[macros::export]
|
||||
pub fn generate_secure_random_string(length: u16) -> String {
|
||||
thread_rng()
|
||||
.sample_iter(Alphanumeric)
|
||||
|
@ -12,7 +12,7 @@ pub fn generate_secure_random_string(length: u16) -> String {
|
|||
.collect()
|
||||
}
|
||||
|
||||
#[crate::export]
|
||||
#[macros::export]
|
||||
pub fn generate_user_token() -> String {
|
||||
generate_secure_random_string(16)
|
||||
}
|
||||
|
|
|
@ -31,18 +31,18 @@
|
|||
"@koa/router": "12.0.1",
|
||||
"@ladjs/koa-views": "9.0.0",
|
||||
"@peertube/http-signature": "1.7.0",
|
||||
"@redocly/openapi-core": "1.14.0",
|
||||
"@redocly/openapi-core": "1.15.0",
|
||||
"@sinonjs/fake-timers": "11.2.2",
|
||||
"adm-zip": "0.5.14",
|
||||
"ajv": "8.16.0",
|
||||
"archiver": "7.0.1",
|
||||
"async-lock": "1.4.0",
|
||||
"async-mutex": "0.5.0",
|
||||
"aws-sdk": "2.1638.0",
|
||||
"aws-sdk": "2.1639.0",
|
||||
"axios": "1.7.2",
|
||||
"backend-rs": "workspace:*",
|
||||
"blurhash": "2.0.5",
|
||||
"bull": "4.12.9",
|
||||
"bull": "4.13.0",
|
||||
"cacheable-lookup": "git+https://github.com/TheEssem/cacheable-lookup.git#dd2fb616366a3c68dcf321a57a67295967b204bf",
|
||||
"cbor-x": "1.5.9",
|
||||
"chalk": "5.3.0",
|
||||
|
@ -123,7 +123,7 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@swc/cli": "0.3.12",
|
||||
"@swc/core": "1.5.27",
|
||||
"@swc/core": "1.5.28",
|
||||
"@types/adm-zip": "0.5.5",
|
||||
"@types/async-lock": "1.4.0",
|
||||
"@types/color-convert": "2.0.3",
|
||||
|
@ -179,7 +179,7 @@
|
|||
"tsconfig-paths": "4.2.0",
|
||||
"type-fest": "4.20.0",
|
||||
"typescript": "5.4.5",
|
||||
"webpack": "5.91.0",
|
||||
"webpack": "5.92.0",
|
||||
"ws": "8.17.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { deleteFile } from "@/services/drive/delete-file.js";
|
||||
import { publishDriveStream } from "@/services/stream.js";
|
||||
import { publishToDriveFileStream, DriveFileEvent } from "backend-rs";
|
||||
import define from "@/server/api/define.js";
|
||||
import { ApiError } from "@/server/api/error.js";
|
||||
import { DriveFiles } from "@/models/index.js";
|
||||
|
@ -51,5 +51,5 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
await deleteFile(file);
|
||||
|
||||
// Publish fileDeleted event
|
||||
publishDriveStream(user.id, "fileDeleted", file.id);
|
||||
publishToDriveFileStream(user.id, DriveFileEvent.Delete, file.id);
|
||||
});
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import { publishDriveStream } from "@/services/stream.js";
|
||||
import { publishToDriveFileStream, DriveFileEvent } from "backend-rs";
|
||||
import { DriveFiles, DriveFolders } from "@/models/index.js";
|
||||
import { config } from "@/config.js";
|
||||
import define from "@/server/api/define.js";
|
||||
import { ApiError } from "@/server/api/error.js";
|
||||
import { toRustObject } from "@/prelude/undefined-to-null.js";
|
||||
|
||||
export const meta = {
|
||||
tags: ["drive"],
|
||||
|
@ -110,7 +111,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
const fileObj = await DriveFiles.pack(file, { self: true });
|
||||
|
||||
// Publish fileUpdated event
|
||||
publishDriveStream(user.id, "fileUpdated", fileObj);
|
||||
publishToDriveFileStream(user.id, DriveFileEvent.Update, toRustObject(file));
|
||||
|
||||
return fileObj;
|
||||
});
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import { publishDriveStream } from "@/services/stream.js";
|
||||
import { publishToDriveFolderStream, DriveFolderEvent } from "backend-rs";
|
||||
import define from "@/server/api/define.js";
|
||||
import { ApiError } from "@/server/api/error.js";
|
||||
import { DriveFolders } from "@/models/index.js";
|
||||
import { genIdAt } from "backend-rs";
|
||||
import { toRustObject } from "@/prelude/undefined-to-null.js";
|
||||
|
||||
export const meta = {
|
||||
tags: ["drive"],
|
||||
|
@ -64,7 +65,11 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
const folderObj = await DriveFolders.pack(folder);
|
||||
|
||||
// Publish folderCreated event
|
||||
publishDriveStream(user.id, "folderCreated", folderObj);
|
||||
publishToDriveFolderStream(
|
||||
user.id,
|
||||
DriveFolderEvent.Create,
|
||||
toRustObject(folder),
|
||||
);
|
||||
|
||||
return folderObj;
|
||||
});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import define from "@/server/api/define.js";
|
||||
import { publishDriveStream } from "@/services/stream.js";
|
||||
import { publishToDriveFolderStream, DriveFolderEvent } from "backend-rs";
|
||||
import { ApiError } from "@/server/api/error.js";
|
||||
import { DriveFolders, DriveFiles } from "@/models/index.js";
|
||||
|
||||
|
@ -56,5 +56,5 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
await DriveFolders.delete(folder.id);
|
||||
|
||||
// Publish folderCreated event
|
||||
publishDriveStream(user.id, "folderDeleted", folder.id);
|
||||
publishToDriveFolderStream(user.id, DriveFolderEvent.Delete, folder.id);
|
||||
});
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { publishDriveStream } from "@/services/stream.js";
|
||||
import { publishToDriveFolderStream, DriveFolderEvent } from "backend-rs";
|
||||
import define from "@/server/api/define.js";
|
||||
import { ApiError } from "@/server/api/error.js";
|
||||
import { DriveFolders } from "@/models/index.js";
|
||||
import { toRustObject } from "@/prelude/undefined-to-null.js";
|
||||
|
||||
export const meta = {
|
||||
tags: ["drive"],
|
||||
|
@ -112,7 +113,11 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
const folderObj = await DriveFolders.pack(folder);
|
||||
|
||||
// Publish folderUpdated event
|
||||
publishDriveStream(user.id, "folderUpdated", folderObj);
|
||||
publishToDriveFolderStream(
|
||||
user.id,
|
||||
DriveFolderEvent.Update,
|
||||
toRustObject(folder),
|
||||
);
|
||||
|
||||
return folderObj;
|
||||
});
|
||||
|
|
|
@ -5,8 +5,14 @@ import { v4 as uuid } from "uuid";
|
|||
import type S3 from "aws-sdk/clients/s3.js"; // TODO: migrate to SDK v3
|
||||
import sharp from "sharp";
|
||||
import { IsNull } from "typeorm";
|
||||
import { publishMainStream, publishDriveStream } from "@/services/stream.js";
|
||||
import { FILE_TYPE_BROWSERSAFE, fetchMeta, genId } from "backend-rs";
|
||||
import { publishMainStream } from "@/services/stream.js";
|
||||
import {
|
||||
DriveFileEvent,
|
||||
FILE_TYPE_BROWSERSAFE,
|
||||
fetchMeta,
|
||||
genId,
|
||||
publishToDriveFileStream,
|
||||
} from "backend-rs";
|
||||
import { contentDisposition } from "@/misc/content-disposition.js";
|
||||
import { getFileInfo } from "@/misc/get-file-info.js";
|
||||
import {
|
||||
|
@ -28,6 +34,7 @@ import { driveLogger } from "./logger.js";
|
|||
import { GenerateVideoThumbnail } from "./generate-video-thumbnail.js";
|
||||
import { deleteFile } from "./delete-file.js";
|
||||
import { inspect } from "node:util";
|
||||
import { toRustObject } from "@/prelude/undefined-to-null.js";
|
||||
|
||||
const logger = driveLogger.createSubLogger("register", "yellow");
|
||||
|
||||
|
@ -658,11 +665,15 @@ export async function addFile({
|
|||
|
||||
logger.info(`drive file has been created ${file.id}`);
|
||||
|
||||
if (user) {
|
||||
if (user != null) {
|
||||
DriveFiles.pack(file, { self: true }).then((packedFile) => {
|
||||
// Publish driveFileCreated event
|
||||
publishMainStream(user.id, "driveFileCreated", packedFile);
|
||||
publishDriveStream(user.id, "fileCreated", packedFile);
|
||||
publishToDriveFileStream(
|
||||
user.id,
|
||||
DriveFileEvent.Create,
|
||||
toRustObject(file),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
import * as mfm from "mfm-js";
|
||||
import {
|
||||
publishMainStream,
|
||||
publishNotesStream,
|
||||
publishNoteStream,
|
||||
} from "@/services/stream.js";
|
||||
import { publishMainStream, publishNoteStream } from "@/services/stream.js";
|
||||
import DeliverManager from "@/remote/activitypub/deliver-manager.js";
|
||||
import renderNote from "@/remote/activitypub/renderer/note.js";
|
||||
import renderCreate from "@/remote/activitypub/renderer/create.js";
|
||||
|
@ -49,6 +45,7 @@ import {
|
|||
genIdAt,
|
||||
isQuote,
|
||||
isSilencedServer,
|
||||
publishToNotesStream,
|
||||
} from "backend-rs";
|
||||
import { countSameRenotes } from "@/misc/count-same-renotes.js";
|
||||
import { deliverToRelays, getCachedRelays } from "../relay.js";
|
||||
|
@ -661,7 +658,7 @@ export default async (
|
|||
30,
|
||||
);
|
||||
}
|
||||
publishNotesStream(noteToPublish);
|
||||
publishToNotesStream(toRustObject(noteToPublish));
|
||||
}
|
||||
} finally {
|
||||
await lock.release();
|
||||
|
|
|
@ -12,7 +12,7 @@ import type {
|
|||
// AntennaStreamTypes,
|
||||
// BroadcastTypes,
|
||||
// ChannelStreamTypes,
|
||||
DriveStreamTypes,
|
||||
// DriveStreamTypes,
|
||||
// GroupMessagingStreamTypes,
|
||||
InternalStreamTypes,
|
||||
MainStreamTypes,
|
||||
|
@ -89,17 +89,18 @@ class Publisher {
|
|||
);
|
||||
};
|
||||
|
||||
public publishDriveStream = <K extends keyof DriveStreamTypes>(
|
||||
userId: User["id"],
|
||||
type: K,
|
||||
value?: DriveStreamTypes[K],
|
||||
): void => {
|
||||
this.publish(
|
||||
`driveStream:${userId}`,
|
||||
type,
|
||||
typeof value === "undefined" ? null : value,
|
||||
);
|
||||
};
|
||||
/* ported to backend-rs */
|
||||
// public publishDriveStream = <K extends keyof DriveStreamTypes>(
|
||||
// userId: User["id"],
|
||||
// type: K,
|
||||
// value?: DriveStreamTypes[K],
|
||||
// ): void => {
|
||||
// this.publish(
|
||||
// `driveStream:${userId}`,
|
||||
// type,
|
||||
// typeof value === "undefined" ? null : value,
|
||||
// );
|
||||
// };
|
||||
|
||||
public publishNoteStream = <K extends keyof NoteStreamTypes>(
|
||||
noteId: Note["id"],
|
||||
|
@ -201,9 +202,10 @@ class Publisher {
|
|||
// );
|
||||
// };
|
||||
|
||||
public publishNotesStream = (note: Note): void => {
|
||||
this.publish("notesStream", null, note);
|
||||
};
|
||||
/* ported to backend-rs */
|
||||
// public publishNotesStream = (note: Note): void => {
|
||||
// this.publish("notesStream", null, note);
|
||||
// };
|
||||
|
||||
/* ported to backend-rs */
|
||||
// public publishAdminStream = <K extends keyof AdminStreamTypes>(
|
||||
|
@ -227,9 +229,9 @@ export const publishInternalEvent = publisher.publishInternalEvent;
|
|||
export const publishUserEvent = publisher.publishUserEvent;
|
||||
// export const publishBroadcastStream = publisher.publishBroadcastStream;
|
||||
export const publishMainStream = publisher.publishMainStream;
|
||||
export const publishDriveStream = publisher.publishDriveStream;
|
||||
// export const publishDriveStream = publisher.publishDriveStream;
|
||||
export const publishNoteStream = publisher.publishNoteStream;
|
||||
export const publishNotesStream = publisher.publishNotesStream;
|
||||
// export const publishNotesStream = publisher.publishNotesStream;
|
||||
export const publishNoteUpdatesStream = publisher.publishNoteUpdatesStream;
|
||||
// export const publishChannelStream = publisher.publishChannelStream;
|
||||
export const publishUserListStream = publisher.publishUserListStream;
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
"qrcode-vue3": "1.6.8",
|
||||
"rollup": "4.17.2",
|
||||
"s-age": "1.1.2",
|
||||
"sass": "1.77.4",
|
||||
"sass": "1.77.5",
|
||||
"seedrandom": "3.0.5",
|
||||
"stringz": "2.1.0",
|
||||
"swiper": "11.1.4",
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@swc/cli": "0.3.12",
|
||||
"@swc/core": "1.5.27",
|
||||
"@swc/core": "1.5.28",
|
||||
"@swc/types": "0.1.8",
|
||||
"@types/jest": "29.5.12",
|
||||
"@types/node": "20.14.2",
|
||||
|
|
11
packages/macro-rs/macros-impl/Cargo.toml
Normal file
11
packages/macro-rs/macros-impl/Cargo.toml
Normal file
|
@ -0,0 +1,11 @@
|
|||
[package]
|
||||
name = "macros-impl"
|
||||
version = "0.0.0"
|
||||
edition = "2021"
|
||||
rust-version = "1.74"
|
||||
|
||||
[dependencies]
|
||||
convert_case = { workspace = true }
|
||||
proc-macro2 = { workspace = true }
|
||||
quote = { workspace = true }
|
||||
syn = { workspace = true, features = ["clone-impls", "extra-traits", "full", "parsing", "printing"] }
|
4
packages/macro-rs/macros-impl/src/lib.rs
Normal file
4
packages/macro-rs/macros-impl/src/lib.rs
Normal file
|
@ -0,0 +1,4 @@
|
|||
#![allow(clippy::items_after_test_module)]
|
||||
|
||||
pub mod napi;
|
||||
mod util;
|
457
packages/macro-rs/macros-impl/src/napi.rs
Normal file
457
packages/macro-rs/macros-impl/src/napi.rs
Normal file
|
@ -0,0 +1,457 @@
|
|||
//! Napi related macros
|
||||
|
||||
use convert_case::{Case, Casing};
|
||||
use proc_macro2::{TokenStream, TokenTree};
|
||||
use quote::{quote, ToTokens};
|
||||
|
||||
/// Creates an extra wrapper function for [napi_derive](https://docs.rs/napi-derive/latest/napi_derive/).
|
||||
///
|
||||
/// The macro is simply converted into `napi_derive::napi(...)`
|
||||
/// if it is not applied to a function.
|
||||
///
|
||||
/// The macro sets the following attributes by default if not specified:
|
||||
/// - `use_nullable = true` (if `object` or `constructor` attribute is specified)
|
||||
/// - `js_name` to the camelCase version of the original function name (for functions)
|
||||
///
|
||||
/// The types of the function arguments is converted with following rules:
|
||||
/// - `&str` and `&mut str` are converted to [`String`]
|
||||
/// - `&[T]` and `&mut [T]` are converted to [`Vec<T>`]
|
||||
/// - `&T` and `&mut T` are converted to `T`
|
||||
/// - Other `T` remains `T`
|
||||
///
|
||||
/// In addition, return type [`Result<T>`] and [`Result<T, E>`] are converted to [`napi::Result<T>`](https://docs.rs/napi/latest/napi/type.Result.html).
|
||||
/// Note that `E` must implement [std::error::Error] trait,
|
||||
/// and `crate::util::error_chain::format_error(error: &dyn std::error::Error) -> String` function must be present.
|
||||
///
|
||||
/// # Examples
|
||||
/// ## Applying the macro to a struct
|
||||
/// ```
|
||||
/// # use macros_impl::napi::napi;
|
||||
/// # macros_impl::macro_doctest!({
|
||||
/// #[macros::napi(object)]
|
||||
/// struct Person {
|
||||
/// id: i32,
|
||||
/// name: String,
|
||||
/// }
|
||||
///
|
||||
/// # }, {
|
||||
/// /******* the code above expands to *******/
|
||||
///
|
||||
/// #[napi_derive::napi(use_nullable = true, object)]
|
||||
/// struct Person {
|
||||
/// id: i32,
|
||||
/// name: String,
|
||||
/// }
|
||||
/// # });
|
||||
/// ```
|
||||
///
|
||||
/// ## Function with explicitly specified `js_name`
|
||||
/// ```
|
||||
/// # use macros_impl::napi::napi;
|
||||
/// # macros_impl::macro_doctest!({
|
||||
/// #[macros::napi(js_name = "add1")]
|
||||
/// pub fn add_one(x: i32) -> i32 {
|
||||
/// x + 1
|
||||
/// }
|
||||
///
|
||||
/// # }, {
|
||||
/// /******* the code above expands to *******/
|
||||
///
|
||||
/// pub fn add_one(x: i32) -> i32 {
|
||||
/// x + 1
|
||||
/// }
|
||||
///
|
||||
/// #[napi_derive::napi(js_name = "add1")]
|
||||
/// pub fn add_one_napi(x: i32) -> i32 {
|
||||
/// add_one(x)
|
||||
/// }
|
||||
/// # });
|
||||
/// ```
|
||||
///
|
||||
/// ## Function with `i32` argument
|
||||
/// ```
|
||||
/// # use macros_impl::napi::napi;
|
||||
/// # macros_impl::macro_doctest!({
|
||||
/// #[macros::napi]
|
||||
/// pub fn add_one(x: i32) -> i32 {
|
||||
/// x + 1
|
||||
/// }
|
||||
///
|
||||
/// # }, {
|
||||
/// /******* the code above expands to *******/
|
||||
///
|
||||
/// pub fn add_one(x: i32) -> i32 {
|
||||
/// x + 1
|
||||
/// }
|
||||
/// #[napi_derive::napi(js_name = "addOne",)]
|
||||
/// pub fn add_one_napi(x: i32) -> i32 {
|
||||
/// add_one(x)
|
||||
/// }
|
||||
/// # });
|
||||
/// ```
|
||||
///
|
||||
/// ## Function with `&str` argument
|
||||
/// ```
|
||||
/// # use macros_impl::napi::napi;
|
||||
/// # macros_impl::macro_doctest!({
|
||||
/// #[macros::napi]
|
||||
/// pub fn concatenate_string(str1: &str, str2: &str) -> String {
|
||||
/// str1.to_owned() + str2
|
||||
/// }
|
||||
///
|
||||
/// # }, {
|
||||
/// /******* the code above expands to *******/
|
||||
///
|
||||
/// pub fn concatenate_string(str1: &str, str2: &str) -> String {
|
||||
/// str1.to_owned() + str2
|
||||
/// }
|
||||
///
|
||||
/// #[napi_derive::napi(js_name = "concatenateString",)]
|
||||
/// pub fn concatenate_string_napi(str1: String, str2: String) -> String {
|
||||
/// concatenate_string(&str1, &str2)
|
||||
/// }
|
||||
/// # });
|
||||
/// ```
|
||||
///
|
||||
/// ## Function with `&[String]` argument
|
||||
/// ```
|
||||
/// # use macros_impl::napi::napi;
|
||||
/// # macros_impl::macro_doctest!({
|
||||
/// #[macros::napi]
|
||||
/// pub fn string_array_length(array: &[String]) -> u32 {
|
||||
/// array.len() as u32
|
||||
/// }
|
||||
///
|
||||
/// # }, {
|
||||
/// /******* the code above expands to *******/
|
||||
///
|
||||
/// pub fn string_array_length(array: &[String]) -> u32 {
|
||||
/// array.len() as u32
|
||||
/// }
|
||||
///
|
||||
/// #[napi_derive::napi(js_name = "stringArrayLength",)]
|
||||
/// pub fn string_array_length_napi(array: Vec<String>) -> u32 {
|
||||
/// string_array_length(&array)
|
||||
/// }
|
||||
/// # });
|
||||
/// ```
|
||||
///
|
||||
/// ## Function with `Result<T, E>` return type
|
||||
/// ```
|
||||
/// # quote::quote! { // prevent compiling the code
|
||||
/// #[derive(thiserror::Error, Debug)]
|
||||
/// pub enum IntegerDivisionError {
|
||||
/// #[error("Divided by zero")]
|
||||
/// DividedByZero,
|
||||
/// #[error("Not divisible with remainder {0}")]
|
||||
/// NotDivisible(i64),
|
||||
/// }
|
||||
/// # };
|
||||
///
|
||||
/// # use macros_impl::napi::napi;
|
||||
/// # macros_impl::macro_doctest!({
|
||||
/// #[macros::napi]
|
||||
/// pub fn integer_divide(dividend: i64, divisor: i64) -> Result<i64, IntegerDivisionError> {
|
||||
/// match divisor {
|
||||
/// 0 => Err(IntegerDivisionError::DividedByZero),
|
||||
/// _ => match dividend % divisor {
|
||||
/// 0 => Ok(dividend / divisor),
|
||||
/// remainder => Err(IntegerDivisionError::NotDivisible(remainder)),
|
||||
/// },
|
||||
/// }
|
||||
/// }
|
||||
/// # }, {
|
||||
///
|
||||
/// /******* the function above expands to *******/
|
||||
///
|
||||
/// pub fn integer_divide(dividend: i64, divisor: i64) -> Result<i64, IntegerDivisionError> {
|
||||
/// match divisor {
|
||||
/// 0 => Err(IntegerDivisionError::DividedByZero),
|
||||
/// _ => match dividend % divisor {
|
||||
/// 0 => Ok(dividend / divisor),
|
||||
/// remainder => Err(IntegerDivisionError::NotDivisible(remainder)),
|
||||
/// },
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// #[napi_derive::napi(js_name = "integerDivide",)]
|
||||
/// pub fn integer_divide_napi(dividend: i64, divisor: i64) -> napi::Result<i64> {
|
||||
/// integer_divide(dividend, divisor)
|
||||
/// .map_err(|err| napi::Error::from_reason(
|
||||
/// format!("\n{}\n", crate::util::error_chain::format_error(&err))
|
||||
/// ))
|
||||
/// }
|
||||
/// # });
|
||||
/// ```
|
||||
///
|
||||
pub fn napi(macro_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
let macro_attr_tokens: Vec<TokenTree> = macro_attr.clone().into_iter().collect();
|
||||
// generated extra macro attr TokenStream (prepended before original input `macro_attr`)
|
||||
let mut extra_macro_attr = TokenStream::new();
|
||||
|
||||
let item: syn::Item =
|
||||
syn::parse2(item).expect("Failed to parse input TokenStream to syn::Item");
|
||||
|
||||
// handle non-functions
|
||||
let syn::Item::Fn(item_fn) = item else {
|
||||
// set `use_nullable = true` if `object` or `constructor` present but not `use_nullable`
|
||||
if macro_attr_tokens.iter().any(|token| {
|
||||
matches!(token, TokenTree::Ident(ident) if ident == "object" || ident == "constructor")
|
||||
}) && !macro_attr_tokens.iter().any(|token| {
|
||||
matches!(token, TokenTree::Ident(ident) if ident == "use_nullable")
|
||||
}) {
|
||||
quote! { use_nullable = true, }.to_tokens(&mut extra_macro_attr);
|
||||
}
|
||||
return quote! {
|
||||
#[napi_derive::napi(#extra_macro_attr #macro_attr)]
|
||||
#item
|
||||
};
|
||||
};
|
||||
|
||||
// handle functions
|
||||
let ident = &item_fn.sig.ident;
|
||||
let item_fn_attrs = &item_fn.attrs;
|
||||
let item_fn_vis = &item_fn.vis;
|
||||
let mut item_fn_sig = item_fn.sig.clone();
|
||||
let mut function_call_modifiers = Vec::<TokenStream>::new();
|
||||
|
||||
// append "_napi" to function name
|
||||
item_fn_sig.ident = syn::parse_str(&format!("{}_napi", &ident)).unwrap();
|
||||
|
||||
// append `.await` to function call in async function
|
||||
if item_fn_sig.asyncness.is_some() {
|
||||
function_call_modifiers.push(quote! {
|
||||
.await
|
||||
});
|
||||
}
|
||||
|
||||
// convert return type `...::Result<T, ...>` to `napi::Result<T>`
|
||||
if let syn::ReturnType::Type(_, ref mut return_type) = item_fn_sig.output {
|
||||
if let Some(result_generic_type) = (|| {
|
||||
let syn::Type::Path(return_type_path) = &**return_type else {
|
||||
return None;
|
||||
};
|
||||
// match a::b::c::Result
|
||||
let last_segment = return_type_path.path.segments.last()?;
|
||||
if last_segment.ident != "Result" {
|
||||
return None;
|
||||
};
|
||||
// extract <T, ...> from Result<T, ...>
|
||||
let syn::PathArguments::AngleBracketed(generic_arguments) = &last_segment.arguments
|
||||
else {
|
||||
return None;
|
||||
};
|
||||
// return T only
|
||||
generic_arguments.args.first()
|
||||
})() {
|
||||
// modify return type
|
||||
*return_type = syn::parse_quote! {
|
||||
napi::Result<#result_generic_type>
|
||||
};
|
||||
// add modifier to function call result
|
||||
function_call_modifiers.push(quote! {
|
||||
.map_err(|err| napi::Error::from_reason(
|
||||
format!("\n{}\n", crate::util::error_chain::format_error(&err))
|
||||
))
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// arguments in function call
|
||||
let called_args: Vec<TokenStream> = item_fn_sig
|
||||
.inputs
|
||||
.iter_mut()
|
||||
.map(|input| match input {
|
||||
// self
|
||||
syn::FnArg::Receiver(arg) => {
|
||||
let mut tokens = TokenStream::new();
|
||||
if let Some((ampersand, lifetime)) = &arg.reference {
|
||||
ampersand.to_tokens(&mut tokens);
|
||||
lifetime.to_tokens(&mut tokens);
|
||||
}
|
||||
arg.mutability.to_tokens(&mut tokens);
|
||||
arg.self_token.to_tokens(&mut tokens);
|
||||
tokens
|
||||
}
|
||||
// typed argument
|
||||
syn::FnArg::Typed(arg) => {
|
||||
match &mut *arg.pat {
|
||||
syn::Pat::Ident(ident) => {
|
||||
let name = &ident.ident;
|
||||
match &*arg.ty {
|
||||
// reference type argument => move ref from sigature to function call
|
||||
syn::Type::Reference(r) => {
|
||||
// add reference anotations to arguments in function call
|
||||
let mut tokens = TokenStream::new();
|
||||
r.and_token.to_tokens(&mut tokens);
|
||||
if let Some(lifetime) = &r.lifetime {
|
||||
lifetime.to_tokens(&mut tokens);
|
||||
}
|
||||
r.mutability.to_tokens(&mut tokens);
|
||||
name.to_tokens(&mut tokens);
|
||||
|
||||
// modify napi argument types in function sigature
|
||||
// (1) add `mut` token to `&mut` type
|
||||
ident.mutability = r.mutability;
|
||||
// (2) remove reference
|
||||
*arg.ty = syn::Type::Verbatim(match &*r.elem {
|
||||
syn::Type::Slice(slice) => {
|
||||
let ty = &*slice.elem;
|
||||
quote! { Vec<#ty> }
|
||||
}
|
||||
_ => {
|
||||
let elem_tokens = r.elem.to_token_stream();
|
||||
match elem_tokens.to_string().as_str() {
|
||||
// &str => String
|
||||
"str" => quote! { String },
|
||||
// &T => T
|
||||
_ => elem_tokens,
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// return arguments in function call
|
||||
tokens
|
||||
}
|
||||
// o.w., return it as is
|
||||
_ => quote! { #name },
|
||||
}
|
||||
}
|
||||
pat => panic!("Unexpected FnArg: {pat:#?}"),
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
// handle macro attr
|
||||
// set js_name if not specified
|
||||
if !macro_attr_tokens
|
||||
.iter()
|
||||
.any(|token| matches!(token, TokenTree::Ident(ident) if ident == "js_name"))
|
||||
{
|
||||
let js_name = ident.to_string().to_case(Case::Camel);
|
||||
quote! { js_name = #js_name, }.to_tokens(&mut extra_macro_attr);
|
||||
}
|
||||
|
||||
quote! {
|
||||
#item_fn
|
||||
|
||||
#[napi_derive::napi(#extra_macro_attr #macro_attr)]
|
||||
#(#item_fn_attrs)*
|
||||
#item_fn_vis #item_fn_sig {
|
||||
#ident(#(#called_args),*)
|
||||
#(#function_call_modifiers)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
crate::macro_unit_tests! {
|
||||
mut_ref_argument: {
|
||||
#[macros::napi]
|
||||
pub fn append_string_and_clone(
|
||||
base_str: &mut String,
|
||||
appended_str: &str,
|
||||
) -> String {
|
||||
base_str.push_str(appended_str);
|
||||
base_str.to_owned()
|
||||
}
|
||||
} generates {
|
||||
#[napi_derive::napi(js_name = "appendStringAndClone", )]
|
||||
pub fn append_string_and_clone_napi(
|
||||
mut base_str: String,
|
||||
appended_str: String,
|
||||
) -> String {
|
||||
append_string_and_clone(&mut base_str, &appended_str)
|
||||
}
|
||||
}
|
||||
|
||||
result_return_type: {
|
||||
#[macros::napi]
|
||||
pub fn integer_divide(
|
||||
dividend: i64,
|
||||
divisor: i64,
|
||||
) -> Result<i64, IntegerDivisionError> {
|
||||
match divisor {
|
||||
0 => Err(IntegerDivisionError::DividedByZero),
|
||||
_ => match dividend % divisor {
|
||||
0 => Ok(dividend / divisor),
|
||||
remainder => Err(IntegerDivisionError::NotDivisible(remainder)),
|
||||
},
|
||||
}
|
||||
}
|
||||
} generates {
|
||||
#[napi_derive::napi(js_name = "integerDivide", )]
|
||||
pub fn integer_divide_napi(
|
||||
dividend: i64,
|
||||
divisor: i64,
|
||||
) -> napi::Result<i64> {
|
||||
integer_divide(dividend, divisor)
|
||||
.map_err(|err| napi::Error::from_reason(
|
||||
format!("\n{}\n", crate::util::error_chain::format_error(&err))
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
async_function: {
|
||||
#[macros::napi]
|
||||
pub async fn async_add_one(x: i32) -> i32 {
|
||||
x + 1
|
||||
}
|
||||
} generates {
|
||||
#[napi_derive::napi(js_name = "asyncAddOne", )]
|
||||
pub async fn async_add_one_napi(x: i32) -> i32 {
|
||||
async_add_one(x)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
slice_type: {
|
||||
#[macros::napi]
|
||||
pub fn string_array_length(array: &[String]) -> u32 {
|
||||
array.len() as u32
|
||||
}
|
||||
} generates {
|
||||
#[napi_derive::napi(js_name = "stringArrayLength", )]
|
||||
pub fn string_array_length_napi(array: Vec<String>) -> u32 {
|
||||
string_array_length(&array)
|
||||
}
|
||||
}
|
||||
|
||||
object_with_explicitly_set_use_nullable: {
|
||||
#[macros::napi(object, use_nullable = false)]
|
||||
struct Person {
|
||||
id: i32,
|
||||
name: Option<String>,
|
||||
}
|
||||
} becomes {
|
||||
#[napi_derive::napi(object, use_nullable = false)]
|
||||
struct Person {
|
||||
id: i32,
|
||||
name: Option<String>,
|
||||
}
|
||||
}
|
||||
|
||||
macro_attr: {
|
||||
#[macros::napi(ts_return_type = "number")]
|
||||
pub fn add_one(x: i32) -> i32 {
|
||||
x + 1
|
||||
}
|
||||
} generates {
|
||||
#[napi_derive::napi(js_name = "addOne", ts_return_type = "number")]
|
||||
pub fn add_one_napi(x: i32) -> i32 {
|
||||
add_one(x)
|
||||
}
|
||||
}
|
||||
|
||||
explicitly_specified_js_name_and_other_macro_attr: {
|
||||
#[macros::napi(ts_return_type = "number", js_name = "add1")]
|
||||
pub fn add_one(x: i32) -> i32 {
|
||||
x + 1
|
||||
}
|
||||
} generates {
|
||||
#[napi_derive::napi(ts_return_type = "number", js_name = "add1")]
|
||||
pub fn add_one_napi(x: i32) -> i32 {
|
||||
add_one(x)
|
||||
}
|
||||
}
|
||||
}
|
3
packages/macro-rs/macros-impl/src/util/mod.rs
Normal file
3
packages/macro-rs/macros-impl/src/util/mod.rs
Normal file
|
@ -0,0 +1,3 @@
|
|||
//! Utilities for developing procedural macros
|
||||
|
||||
mod tester;
|
122
packages/macro-rs/macros-impl/src/util/tester.rs
Normal file
122
packages/macro-rs/macros-impl/src/util/tester.rs
Normal file
|
@ -0,0 +1,122 @@
|
|||
//! Macros for testing procedural macros
|
||||
|
||||
/// Tests if the macro expands correctly.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use macros_impl::napi::napi;
|
||||
///
|
||||
/// macros_impl::macro_doctest!({
|
||||
/// #[macros::napi(object)]
|
||||
/// struct Person {
|
||||
/// id: i32,
|
||||
/// name: String,
|
||||
/// }
|
||||
/// }, {
|
||||
/// #[napi_derive::napi(use_nullable = true, object)]
|
||||
/// struct Person {
|
||||
/// id: i32,
|
||||
/// name: String,
|
||||
/// }
|
||||
/// });
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! macro_doctest {
|
||||
({
|
||||
#[macros :: $macro_name:ident $(( $($attr:tt)* ))?]
|
||||
$($item:tt)*
|
||||
}, {
|
||||
$($expanded:tt)*
|
||||
}) => {
|
||||
assert_eq!(
|
||||
::std::string::ToString::to_string(
|
||||
&$macro_name(
|
||||
::quote::quote!($( $($attr)* )?),
|
||||
::quote::quote!($($item)*),
|
||||
)
|
||||
),
|
||||
::std::string::ToString::to_string(
|
||||
&::quote::quote!($($expanded)*)
|
||||
)
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
/// Creates unit tests for macros.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// macros_impl::macro_unit_tests! {
|
||||
/// add1_becomes: {
|
||||
/// #[macros::napi(js_name = "add1")]
|
||||
/// pub fn add_one(x: i32) -> i32 {
|
||||
/// x + 1
|
||||
/// }
|
||||
/// } becomes { // the code above should expand to the following code
|
||||
/// pub fn add_one(x: i32) -> i32 {
|
||||
/// x + 1
|
||||
/// }
|
||||
///
|
||||
/// #[napi_derive::napi(js_name = "add1")]
|
||||
/// pub fn add_one_napi(x: i32) -> i32 {
|
||||
/// add_one(x)
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // this test case is equivalent to `add1_becomes`
|
||||
/// add1_generates: {
|
||||
/// #[macros::napi(js_name = "add1")]
|
||||
/// pub fn add_one(x: i32) -> i32 {
|
||||
/// x + 1
|
||||
/// }
|
||||
/// } generates { // the code above should generate the following code
|
||||
/// #[napi_derive::napi(js_name = "add1")]
|
||||
/// pub fn add_one_napi(x: i32) -> i32 {
|
||||
/// add_one(x)
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! macro_unit_tests {
|
||||
(@test $macro_name:ident($attr:ident, $item:ident) becomes $expanded:ident) => {
|
||||
assert_eq!(
|
||||
::std::format!("{}", $macro_name($attr, $item)),
|
||||
::std::format!("{}", $expanded),
|
||||
);
|
||||
};
|
||||
(@test $macro_name:ident($attr:ident, $item:ident) generates $expanded:ident) => {
|
||||
let item_str = format!("{}", $item);
|
||||
assert_eq!(
|
||||
::std::format!("{}", $macro_name($attr, $item)),
|
||||
::std::format!("{} {}", item_str, $expanded),
|
||||
);
|
||||
};
|
||||
|
||||
(
|
||||
$(
|
||||
$test_name:ident : {
|
||||
#[macros :: $macro_name:ident $(( $($attr:tt)* ))?]
|
||||
$($item:tt)*
|
||||
} $op:tt {
|
||||
$($expanded:tt)*
|
||||
}
|
||||
)*
|
||||
) => {
|
||||
#[cfg(test)]
|
||||
mod unit_test {
|
||||
use super::*;
|
||||
|
||||
$(
|
||||
#[test]
|
||||
fn $test_name() {
|
||||
let attr = ::quote::quote!($( $($attr)* )?);
|
||||
let item = ::quote::quote!($($item)*);
|
||||
let expanded = ::quote::quote!($($expanded)*);
|
||||
|
||||
$crate::macro_unit_tests!(@test $macro_name(attr, item) $op expanded);
|
||||
}
|
||||
)*
|
||||
}
|
||||
};
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
[package]
|
||||
name = "macro-rs"
|
||||
name = "macros"
|
||||
version = "0.0.0"
|
||||
edition = "2021"
|
||||
rust-version = "1.74"
|
||||
|
@ -8,14 +8,9 @@ rust-version = "1.74"
|
|||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
convert_case = { workspace = true }
|
||||
macros-impl = { workspace = true }
|
||||
|
||||
proc-macro2 = { workspace = true }
|
||||
quote = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true, features = ["std"] }
|
||||
syn = { workspace = true, features = ["extra-traits", "full"] }
|
||||
|
||||
[dev-dependencies]
|
||||
thiserror = { workspace = true }
|
||||
napi = { workspace = true }
|
||||
napi-derive = { workspace = true, features = ["noop"] }
|
88
packages/macro-rs/macros/src/helper.rs
Normal file
88
packages/macro-rs/macros/src/helper.rs
Normal file
|
@ -0,0 +1,88 @@
|
|||
//! Helper macros for developing procedural macros
|
||||
|
||||
#[doc(hidden)]
|
||||
pub(crate) use quote::quote;
|
||||
|
||||
/// Defines wrapper #\[proc_macro_attribute]s.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```ignore
|
||||
/// define_wrapper_proc_macro_attributes! {
|
||||
/// // expand `#[export(attr)]` to
|
||||
/// // ```
|
||||
/// // #[cfg_attr(feature = "napi", macros::napi(#attr))]
|
||||
/// // ```
|
||||
/// export(attr, item) {
|
||||
/// #[cfg_attr(feature = "napi", macros::napi(#attr))]
|
||||
/// #item
|
||||
/// }
|
||||
///
|
||||
/// // expand `#[ts_export(attr)]` to
|
||||
/// // ```
|
||||
/// // #[cfg(feature = "napi")]
|
||||
/// // #[macros::napi(#attr)]
|
||||
/// // ```
|
||||
/// ts_export(attr, item) {
|
||||
/// #[cfg(feature = "napi")]
|
||||
/// #[macros::napi(#attr)]
|
||||
/// #item
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
macro_rules! define_wrapper_proc_macro_attributes {
|
||||
(
|
||||
$(
|
||||
$(#[$meta:meta])*
|
||||
$macro_name:ident ($arg_attr:ident, $arg_item:ident) {
|
||||
$($body:tt)*
|
||||
}
|
||||
)*
|
||||
) => {
|
||||
$(
|
||||
$(#[$meta])*
|
||||
#[proc_macro_attribute]
|
||||
pub fn $macro_name(
|
||||
attr: ::proc_macro::TokenStream,
|
||||
item: ::proc_macro::TokenStream,
|
||||
) -> ::proc_macro::TokenStream {
|
||||
let $arg_attr: ::proc_macro2::TokenStream = attr.into();
|
||||
let $arg_item: ::proc_macro2::TokenStream = item.into();
|
||||
::quote::quote!($($body)*).into()
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
pub(crate) use define_wrapper_proc_macro_attributes;
|
||||
|
||||
/// Wraps and exports #\[proc_macro_attribute] implementation.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```ignore
|
||||
/// reexport_proc_macro_attributes! {
|
||||
/// // wrap and export [macros_impl::napi::napi] as #[macros::napi]
|
||||
/// macros_impl::napi::napi as napi
|
||||
///
|
||||
/// // wrap and export [macros_impl::errors::errors] as #[macros::errors]
|
||||
/// macros_impl::errors::errors as errors
|
||||
/// }
|
||||
/// ```
|
||||
macro_rules! reexport_proc_macro_attributes {
|
||||
(
|
||||
$(
|
||||
$(#[$meta:meta])*
|
||||
$impl_path:path as $macro_name:ident
|
||||
)*
|
||||
) => {
|
||||
$(
|
||||
$(#[$meta])*
|
||||
#[proc_macro_attribute]
|
||||
pub fn $macro_name(
|
||||
attr: ::proc_macro::TokenStream,
|
||||
item: ::proc_macro::TokenStream,
|
||||
) -> ::proc_macro::TokenStream {
|
||||
$impl_path(attr.into(), item.into()).into()
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
pub(crate) use reexport_proc_macro_attributes;
|
81
packages/macro-rs/macros/src/lib.rs
Normal file
81
packages/macro-rs/macros/src/lib.rs
Normal file
|
@ -0,0 +1,81 @@
|
|||
mod helper;
|
||||
use helper::*;
|
||||
|
||||
/// Reads the version field in the project root package.json at compile time.
|
||||
///
|
||||
/// # Example
|
||||
/// You can get a compile-time constant version number using this macro:
|
||||
/// ```
|
||||
/// # use macros::read_version_from_package_json;
|
||||
/// // VERSION == "YYYYMMDD" (or "YYYYMMDD-X")
|
||||
/// const VERSION: &str = read_version_from_package_json!();
|
||||
/// ```
|
||||
#[proc_macro]
|
||||
pub fn read_version_from_package_json(_item: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
#[derive(serde::Deserialize)]
|
||||
struct PackageJson {
|
||||
version: String,
|
||||
}
|
||||
|
||||
let file = std::fs::File::open("package.json").expect("Failed to open package.json");
|
||||
let json: PackageJson = serde_json::from_reader(file).unwrap();
|
||||
let version = &json.version;
|
||||
|
||||
quote!(#version).into()
|
||||
}
|
||||
|
||||
define_wrapper_proc_macro_attributes! {
|
||||
/// Exports an enum to TypeScript, and derive [Clone].
|
||||
///
|
||||
/// You need this macro because [`napi_derive::napi`](https://docs.rs/napi-derive/latest/napi_derive/attr.napi.html)
|
||||
/// automatically derives the [Clone] trait for enums and causes conflicts.
|
||||
///
|
||||
/// This is a wrapper of [`napi_derive::napi`](https://docs.rs/napi-derive/latest/napi_derive/attr.napi.html)
|
||||
/// that expands to
|
||||
/// ```no_run
|
||||
/// #[cfg_attr(not(feature = "napi"), derive(Clone))]
|
||||
/// #[cfg_attr(feature = "napi", napi_derive::napi(attr))]
|
||||
/// # enum E {} // to work around doc test compilation error
|
||||
/// ```
|
||||
/// where `attr` is given attribute(s).
|
||||
derive_clone_and_export(attr, item) {
|
||||
#[cfg_attr(not(feature = "napi"), derive(Clone))]
|
||||
#[cfg_attr(feature = "napi", napi_derive::napi(#attr))]
|
||||
#item
|
||||
}
|
||||
|
||||
/// Exports a function, struct, enum, const, etc. to TypeScript.
|
||||
///
|
||||
/// This is a wrapper of [macro@napi] that expands to
|
||||
/// ```no_run
|
||||
/// #[cfg_attr(feature = "napi", macros::napi(attr))]
|
||||
/// # fn f() {} // to work around doc test compilation error
|
||||
/// ```
|
||||
/// where `attr` is given attribute(s). See [macro@napi] for more details.
|
||||
export(attr, item) {
|
||||
#[cfg_attr(feature = "napi", macros::napi(#attr))]
|
||||
#item
|
||||
}
|
||||
|
||||
/// Exports a function, struct, enum, const, etc. to TypeScript
|
||||
/// and make it unable to use in Rust.
|
||||
///
|
||||
/// This is a wrapper of [macro@napi] that expands to
|
||||
/// ```no_run
|
||||
/// #[cfg(feature = "napi")]
|
||||
/// #[macros::napi(attr)]
|
||||
/// # fn f() {} // to work around doc test compilation error
|
||||
/// ```
|
||||
/// where `attr` is given attribute(s). See [macro@napi] for more details.
|
||||
ts_export(attr, item) {
|
||||
#[cfg(feature = "napi")]
|
||||
#[macros::napi(#attr)]
|
||||
#item
|
||||
}
|
||||
}
|
||||
|
||||
reexport_proc_macro_attributes! {
|
||||
/// Creates an extra wrapper function for [napi_derive](https://docs.rs/napi-derive/latest/napi_derive/).
|
||||
/// See [macros_impl::napi::napi] for details.
|
||||
macros_impl::napi::napi as napi
|
||||
}
|
|
@ -1,680 +0,0 @@
|
|||
use convert_case::{Case, Casing};
|
||||
use proc_macro2::{TokenStream, TokenTree};
|
||||
use quote::{quote, ToTokens};
|
||||
|
||||
/// Read the version field in the project root package.json at compile time
|
||||
///
|
||||
/// # Example
|
||||
/// You can get a compile-time constant version number using this macro:
|
||||
/// ```
|
||||
/// # use macro_rs::read_version_from_package_json;
|
||||
/// // VERSION == "YYYYMMDD" (or "YYYYMMDD-X")
|
||||
/// const VERSION: &str = read_version_from_package_json!();
|
||||
/// ```
|
||||
#[proc_macro]
|
||||
pub fn read_version_from_package_json(_item: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
#[derive(serde::Deserialize)]
|
||||
struct PackageJson {
|
||||
version: String,
|
||||
}
|
||||
|
||||
let file = std::fs::File::open("package.json").expect("Failed to open package.json");
|
||||
let json: PackageJson = serde_json::from_reader(file).unwrap();
|
||||
let version = &json.version;
|
||||
|
||||
quote! { #version }.into()
|
||||
}
|
||||
|
||||
/// Export an enum to TypeScript, and derive [Clone].
|
||||
///
|
||||
/// You need this macro because [`napi_derive::napi`](https://docs.rs/napi-derive/latest/napi_derive/attr.napi.html)
|
||||
/// automatically derives the [Clone] trait for enums and causes conflicts.
|
||||
///
|
||||
/// This is a wrapper of [`napi_derive::napi`](https://docs.rs/napi-derive/latest/napi_derive/attr.napi.html)
|
||||
/// that expands to
|
||||
/// ```no_run
|
||||
/// #[cfg_attr(not(feature = "napi"), derive(Clone))]
|
||||
/// #[cfg_attr(feature = "napi", napi_derive::napi(attr))]
|
||||
/// # enum E {} // to work around doc test compilation error
|
||||
/// ```
|
||||
/// where `attr` is given attribute(s).
|
||||
#[proc_macro_attribute]
|
||||
pub fn derive_clone_and_export(
|
||||
attr: proc_macro::TokenStream,
|
||||
item: proc_macro::TokenStream,
|
||||
) -> proc_macro::TokenStream {
|
||||
let attr: TokenStream = attr.into();
|
||||
let item: TokenStream = item.into();
|
||||
|
||||
quote! {
|
||||
#[cfg_attr(not(feature = "napi"), derive(Clone))]
|
||||
#[cfg_attr(feature = "napi", napi_derive::napi(#attr))]
|
||||
#item
|
||||
}
|
||||
.into()
|
||||
}
|
||||
|
||||
/// Export a function, struct, enum, const, etc. to TypeScript.
|
||||
///
|
||||
/// This is a wrapper of [macro@napi] that expands to
|
||||
/// ```no_run
|
||||
/// #[cfg_attr(feature = "napi", macro_rs::napi(attr))]
|
||||
/// # fn f() {} // to work around doc test compilation error
|
||||
/// ```
|
||||
/// where `attr` is given attribute(s). See [macro@napi] for more details.
|
||||
#[proc_macro_attribute]
|
||||
pub fn export(
|
||||
attr: proc_macro::TokenStream,
|
||||
item: proc_macro::TokenStream,
|
||||
) -> proc_macro::TokenStream {
|
||||
let attr: TokenStream = attr.into();
|
||||
let item: TokenStream = item.into();
|
||||
|
||||
quote! {
|
||||
#[cfg_attr(feature = "napi", macro_rs::napi(#attr))]
|
||||
#item
|
||||
}
|
||||
.into()
|
||||
}
|
||||
|
||||
/// Export a function, struct, enum, const, etc. to TypeScript
|
||||
/// and make it unable to use in Rust.
|
||||
///
|
||||
/// This is a wrapper of [macro@napi] that expands to
|
||||
/// ```no_run
|
||||
/// #[cfg(feature = "napi")]
|
||||
/// #[macro_rs::napi(attr)]
|
||||
/// # fn f() {} // to work around doc test compilation error
|
||||
/// ```
|
||||
/// where `attr` is given attribute(s). See [macro@napi] for more details.
|
||||
#[proc_macro_attribute]
|
||||
pub fn ts_export(
|
||||
attr: proc_macro::TokenStream,
|
||||
item: proc_macro::TokenStream,
|
||||
) -> proc_macro::TokenStream {
|
||||
let attr: TokenStream = attr.into();
|
||||
let item: TokenStream = item.into();
|
||||
|
||||
quote! {
|
||||
#[cfg(feature = "napi")]
|
||||
#[macro_rs::napi(#attr)]
|
||||
#item
|
||||
}
|
||||
.into()
|
||||
}
|
||||
|
||||
/// Creates an extra wrapper function for [napi_derive](https://docs.rs/napi-derive/latest/napi_derive/).
|
||||
///
|
||||
/// The macro is simply converted into `napi_derive::napi(...)`
|
||||
/// if it is not applied to a function.
|
||||
///
|
||||
/// The macro sets the following attributes by default if not specified:
|
||||
/// - `use_nullable = true` (if `object` or `constructor` attribute is specified)
|
||||
/// - `js_name` to the camelCase version of the original function name (for functions)
|
||||
///
|
||||
/// The types of the function arguments is converted with following rules:
|
||||
/// - `&str` and `&mut str` are converted to [`String`]
|
||||
/// - `&[T]` and `&mut [T]` are converted to [`Vec<T>`]
|
||||
/// - `&T` and `&mut T` are converted to `T`
|
||||
/// - Other `T` remains `T`
|
||||
///
|
||||
/// In addition, return type [`Result<T>`] and [`Result<T, E>`] are converted to [`napi::Result<T>`](https://docs.rs/napi/latest/napi/type.Result.html).
|
||||
/// Note that `E` must implement [`std::string::ToString`] trait.
|
||||
///
|
||||
/// # Examples
|
||||
/// ## Applying the macro to a struct
|
||||
/// ```
|
||||
/// #[macro_rs::napi(object)]
|
||||
/// struct Person {
|
||||
/// id: i32,
|
||||
/// name: String,
|
||||
/// }
|
||||
/// ```
|
||||
/// simply becomes
|
||||
/// ```
|
||||
/// #[napi_derive::napi(use_nullable = true, object)]
|
||||
/// struct Person {
|
||||
/// id: i32,
|
||||
/// name: String,
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ## Function with explicitly specified `js_name`
|
||||
/// ```
|
||||
/// #[macro_rs::napi(js_name = "add1")]
|
||||
/// pub fn add_one(x: i32) -> i32 {
|
||||
/// x + 1
|
||||
/// }
|
||||
/// ```
|
||||
/// generates
|
||||
/// ```
|
||||
/// # pub fn add_one(x: i32) -> i32 {
|
||||
/// # x + 1
|
||||
/// # }
|
||||
/// #[napi_derive::napi(js_name = "add1",)]
|
||||
/// pub fn add_one_napi(x: i32) -> i32 {
|
||||
/// add_one(x)
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ## Function with `i32` argument
|
||||
/// ```
|
||||
/// #[macro_rs::napi]
|
||||
/// pub fn add_one(x: i32) -> i32 {
|
||||
/// x + 1
|
||||
/// }
|
||||
/// ```
|
||||
/// generates
|
||||
/// ```
|
||||
/// # pub fn add_one(x: i32) -> i32 {
|
||||
/// # x + 1
|
||||
/// # }
|
||||
/// #[napi_derive::napi(js_name = "addOne",)]
|
||||
/// pub fn add_one_napi(x: i32) -> i32 {
|
||||
/// add_one(x)
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ## Function with `&str` argument
|
||||
/// ```
|
||||
/// #[macro_rs::napi]
|
||||
/// pub fn concatenate_string(str1: &str, str2: &str) -> String {
|
||||
/// str1.to_owned() + str2
|
||||
/// }
|
||||
/// ```
|
||||
/// generates
|
||||
/// ```
|
||||
/// # pub fn concatenate_string(str1: &str, str2: &str) -> String {
|
||||
/// # str1.to_owned() + str2
|
||||
/// # }
|
||||
/// #[napi_derive::napi(js_name = "concatenateString",)]
|
||||
/// pub fn concatenate_string_napi(str1: String, str2: String) -> String {
|
||||
/// concatenate_string(&str1, &str2)
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ## Function with `&[String]` argument
|
||||
/// ```
|
||||
/// #[macro_rs::napi]
|
||||
/// pub fn string_array_length(array: &[String]) -> u32 {
|
||||
/// array.len() as u32
|
||||
/// }
|
||||
/// ```
|
||||
/// generates
|
||||
/// ```
|
||||
/// # pub fn string_array_length(array: &[String]) -> u32 {
|
||||
/// # array.len() as u32
|
||||
/// # }
|
||||
/// #[napi_derive::napi(js_name = "stringArrayLength",)]
|
||||
/// pub fn string_array_length_napi(array: Vec<String>) -> u32 {
|
||||
/// string_array_length(&array)
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ## Function with `Result<T, E>` return type
|
||||
/// ```ignore
|
||||
/// #[derive(thiserror::Error, Debug)]
|
||||
/// pub enum IntegerDivisionError {
|
||||
/// #[error("Divided by zero")]
|
||||
/// DividedByZero,
|
||||
/// #[error("Not divisible with remainder = {0}")]
|
||||
/// NotDivisible(i64),
|
||||
/// }
|
||||
///
|
||||
/// #[macro_rs::napi]
|
||||
/// pub fn integer_divide(dividend: i64, divisor: i64) -> Result<i64, IntegerDivisionError> {
|
||||
/// match divisor {
|
||||
/// 0 => Err(IntegerDivisionError::DividedByZero),
|
||||
/// _ => match dividend % divisor {
|
||||
/// 0 => Ok(dividend / divisor),
|
||||
/// remainder => Err(IntegerDivisionError::NotDivisible(remainder)),
|
||||
/// },
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
/// generates
|
||||
/// ```ignore
|
||||
/// # #[derive(thiserror::Error, Debug)]
|
||||
/// # pub enum IntegerDivisionError {
|
||||
/// # #[error("Divided by zero")]
|
||||
/// # DividedByZero,
|
||||
/// # #[error("Not divisible with remainder = {0}")]
|
||||
/// # NotDivisible(i64),
|
||||
/// # }
|
||||
/// # pub fn integer_divide(dividend: i64, divisor: i64) -> Result<i64, IntegerDivisionError> {
|
||||
/// # match divisor {
|
||||
/// # 0 => Err(IntegerDivisionError::DividedByZero),
|
||||
/// # _ => match dividend % divisor {
|
||||
/// # 0 => Ok(dividend / divisor),
|
||||
/// # remainder => Err(IntegerDivisionError::NotDivisible(remainder)),
|
||||
/// # },
|
||||
/// # }
|
||||
/// # }
|
||||
/// #[napi_derive::napi(js_name = "integerDivide",)]
|
||||
/// pub fn integer_divide_napi(dividend: i64, divisor: i64) -> napi::Result<i64> {
|
||||
/// integer_divide(dividend, divisor).map_err(|err| napi::Error::from_reason(crate::util::error_chain::format_error(&err)))
|
||||
/// }
|
||||
/// ```
|
||||
#[proc_macro_attribute]
|
||||
pub fn napi(
|
||||
attr: proc_macro::TokenStream,
|
||||
item: proc_macro::TokenStream,
|
||||
) -> proc_macro::TokenStream {
|
||||
napi_impl(attr.into(), item.into()).into()
|
||||
}
|
||||
|
||||
fn napi_impl(macro_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
let macro_attr_tokens: Vec<TokenTree> = macro_attr.clone().into_iter().collect();
|
||||
// generated extra macro attr TokenStream (prepended before original input `macro_attr`)
|
||||
let mut extra_macro_attr = TokenStream::new();
|
||||
|
||||
let item: syn::Item =
|
||||
syn::parse2(item).expect("Failed to parse input TokenStream to syn::Item");
|
||||
|
||||
// handle non-functions
|
||||
let syn::Item::Fn(item_fn) = item else {
|
||||
// append `use_nullable = true` if `object` or `constructor` present but not `use_nullable`
|
||||
if macro_attr_tokens.iter().any(|token| {
|
||||
matches!(token, TokenTree::Ident(ident) if ident == "object" || ident == "constructor")
|
||||
}) && !macro_attr_tokens.iter().any(|token| {
|
||||
matches!(token, TokenTree::Ident(ident) if ident == "use_nullable")
|
||||
}) {
|
||||
quote! { use_nullable = true, }.to_tokens(&mut extra_macro_attr);
|
||||
}
|
||||
return quote! {
|
||||
#[napi_derive::napi(#extra_macro_attr #macro_attr)]
|
||||
#item
|
||||
};
|
||||
};
|
||||
|
||||
// handle functions
|
||||
let ident = &item_fn.sig.ident;
|
||||
let item_fn_attrs = &item_fn.attrs;
|
||||
let item_fn_vis = &item_fn.vis;
|
||||
let mut item_fn_sig = item_fn.sig.clone();
|
||||
let mut function_call_modifiers = Vec::<TokenStream>::new();
|
||||
|
||||
// append "_napi" to function name
|
||||
item_fn_sig.ident = syn::parse_str(&format!("{}_napi", &ident)).unwrap();
|
||||
|
||||
// append `.await` to function call in async function
|
||||
if item_fn_sig.asyncness.is_some() {
|
||||
function_call_modifiers.push(quote! {
|
||||
.await
|
||||
});
|
||||
}
|
||||
|
||||
// convert return type `...::Result<T, ...>` to `napi::Result<T>`
|
||||
if let syn::ReturnType::Type(_, ref mut return_type) = item_fn_sig.output {
|
||||
if let Some(result_generic_type) = (|| {
|
||||
let syn::Type::Path(return_type_path) = &**return_type else {
|
||||
return None;
|
||||
};
|
||||
// match a::b::c::Result
|
||||
let last_segment = return_type_path.path.segments.last()?;
|
||||
if last_segment.ident != "Result" {
|
||||
return None;
|
||||
};
|
||||
// extract <T, ...> from Result<T, ...>
|
||||
let syn::PathArguments::AngleBracketed(generic_arguments) = &last_segment.arguments
|
||||
else {
|
||||
return None;
|
||||
};
|
||||
// return T only
|
||||
generic_arguments.args.first()
|
||||
})() {
|
||||
// modify return type
|
||||
*return_type = syn::parse_quote! {
|
||||
napi::Result<#result_generic_type>
|
||||
};
|
||||
// add modifier to function call result
|
||||
function_call_modifiers.push(quote! {
|
||||
.map_err(|err| napi::Error::from_reason(crate::util::error_chain::format_error(&err)))
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// arguments in function call
|
||||
let called_args: Vec<TokenStream> = item_fn_sig
|
||||
.inputs
|
||||
.iter_mut()
|
||||
.map(|input| match input {
|
||||
// self
|
||||
syn::FnArg::Receiver(arg) => {
|
||||
let mut tokens = TokenStream::new();
|
||||
if let Some((ampersand, lifetime)) = &arg.reference {
|
||||
ampersand.to_tokens(&mut tokens);
|
||||
lifetime.to_tokens(&mut tokens);
|
||||
}
|
||||
arg.mutability.to_tokens(&mut tokens);
|
||||
arg.self_token.to_tokens(&mut tokens);
|
||||
tokens
|
||||
}
|
||||
// typed argument
|
||||
syn::FnArg::Typed(arg) => {
|
||||
match &mut *arg.pat {
|
||||
syn::Pat::Ident(ident) => {
|
||||
let name = &ident.ident;
|
||||
match &*arg.ty {
|
||||
// reference type argument => move ref from sigature to function call
|
||||
syn::Type::Reference(r) => {
|
||||
// add reference anotations to arguments in function call
|
||||
let mut tokens = TokenStream::new();
|
||||
r.and_token.to_tokens(&mut tokens);
|
||||
if let Some(lifetime) = &r.lifetime {
|
||||
lifetime.to_tokens(&mut tokens);
|
||||
}
|
||||
r.mutability.to_tokens(&mut tokens);
|
||||
name.to_tokens(&mut tokens);
|
||||
|
||||
// modify napi argument types in function sigature
|
||||
// (1) add `mut` token to `&mut` type
|
||||
ident.mutability = r.mutability;
|
||||
// (2) remove reference
|
||||
*arg.ty = syn::Type::Verbatim(match &*r.elem {
|
||||
syn::Type::Slice(slice) => {
|
||||
let ty = &*slice.elem;
|
||||
quote! { Vec<#ty> }
|
||||
}
|
||||
_ => {
|
||||
let elem_tokens = r.elem.to_token_stream();
|
||||
match elem_tokens.to_string().as_str() {
|
||||
// &str => String
|
||||
"str" => quote! { String },
|
||||
// &T => T
|
||||
_ => elem_tokens,
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// return arguments in function call
|
||||
tokens
|
||||
}
|
||||
// o.w., return it as is
|
||||
_ => quote! { #name },
|
||||
}
|
||||
}
|
||||
pat => panic!("Unexpected FnArg: {pat:#?}"),
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
// handle macro attr
|
||||
// append js_name if not specified
|
||||
if !macro_attr_tokens
|
||||
.iter()
|
||||
.any(|token| matches!(token, TokenTree::Ident(ident) if ident == "js_name"))
|
||||
{
|
||||
let js_name = ident.to_string().to_case(Case::Camel);
|
||||
quote! { js_name = #js_name, }.to_tokens(&mut extra_macro_attr);
|
||||
}
|
||||
|
||||
quote! {
|
||||
#item_fn
|
||||
|
||||
#[napi_derive::napi(#extra_macro_attr #macro_attr)]
|
||||
#(#item_fn_attrs)*
|
||||
#item_fn_vis #item_fn_sig {
|
||||
#ident(#(#called_args),*)
|
||||
#(#function_call_modifiers)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
|
||||
macro_rules! test_macro_becomes {
|
||||
($source:expr, $generated:expr) => {
|
||||
assert_eq!(
|
||||
super::napi_impl(TokenStream::new(), $source).to_string(),
|
||||
$generated.to_string(),
|
||||
)
|
||||
};
|
||||
($macro_attr:expr, $source:expr, $generated:expr) => {
|
||||
assert_eq!(
|
||||
super::napi_impl($macro_attr, $source).to_string(),
|
||||
$generated.to_string(),
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! test_macro_generates {
|
||||
($source:expr, $generated:expr) => {
|
||||
assert_eq!(
|
||||
super::napi_impl(TokenStream::new(), $source).to_string(),
|
||||
format!("{} {}", $source, $generated),
|
||||
)
|
||||
};
|
||||
($macro_attr:expr, $source:expr, $generated:expr) => {
|
||||
assert_eq!(
|
||||
super::napi_impl($macro_attr, $source).to_string(),
|
||||
format!("{} {}", $source, $generated),
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn primitive_argument() {
|
||||
test_macro_generates!(
|
||||
quote! {
|
||||
pub fn add_one(x: i32) -> i32 {
|
||||
x + 1
|
||||
}
|
||||
},
|
||||
quote! {
|
||||
#[napi_derive::napi(js_name = "addOne", )]
|
||||
pub fn add_one_napi(x: i32) -> i32 {
|
||||
add_one(x)
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn str_ref_argument() {
|
||||
test_macro_generates!(
|
||||
quote! {
|
||||
pub fn concatenate_string(str1: &str, str2: &str) -> String {
|
||||
str1.to_owned() + str2
|
||||
}
|
||||
},
|
||||
quote! {
|
||||
#[napi_derive::napi(js_name = "concatenateString", )]
|
||||
pub fn concatenate_string_napi(str1: String, str2: String) -> String {
|
||||
concatenate_string(&str1, &str2)
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mut_ref_argument() {
|
||||
test_macro_generates!(
|
||||
quote! {
|
||||
pub fn append_string_and_clone(
|
||||
base_str: &mut String,
|
||||
appended_str: &str,
|
||||
) -> String {
|
||||
base_str.push_str(appended_str);
|
||||
base_str.to_owned()
|
||||
}
|
||||
},
|
||||
quote! {
|
||||
#[napi_derive::napi(js_name = "appendStringAndClone", )]
|
||||
pub fn append_string_and_clone_napi(
|
||||
mut base_str: String,
|
||||
appended_str: String,
|
||||
) -> String {
|
||||
append_string_and_clone(&mut base_str, &appended_str)
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn result_return_type() {
|
||||
test_macro_generates!(
|
||||
quote! {
|
||||
pub fn integer_divide(
|
||||
dividend: i64,
|
||||
divisor: i64,
|
||||
) -> Result<i64, IntegerDivisionError> {
|
||||
match divisor {
|
||||
0 => Err(IntegerDivisionError::DividedByZero),
|
||||
_ => match dividend % divisor {
|
||||
0 => Ok(dividend / divisor),
|
||||
remainder => Err(IntegerDivisionError::NotDivisible(remainder)),
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
quote! {
|
||||
#[napi_derive::napi(js_name = "integerDivide", )]
|
||||
pub fn integer_divide_napi(
|
||||
dividend: i64,
|
||||
divisor: i64,
|
||||
) -> napi::Result<i64> {
|
||||
integer_divide(dividend, divisor)
|
||||
.map_err(|err| napi::Error::from_reason(crate::util::error_chain::format_error(&err)))
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn async_function() {
|
||||
test_macro_generates!(
|
||||
quote! {
|
||||
pub async fn async_add_one(x: i32) -> i32 {
|
||||
x + 1
|
||||
}
|
||||
},
|
||||
quote! {
|
||||
#[napi_derive::napi(js_name = "asyncAddOne", )]
|
||||
pub async fn async_add_one_napi(x: i32) -> i32 {
|
||||
async_add_one(x)
|
||||
.await
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn slice_type() {
|
||||
test_macro_generates!(
|
||||
quote! {
|
||||
pub fn string_array_length(array: &[String]) -> u32 {
|
||||
array.len() as u32
|
||||
}
|
||||
},
|
||||
quote! {
|
||||
#[napi_derive::napi(js_name = "stringArrayLength", )]
|
||||
pub fn string_array_length_napi(array: Vec<String>) -> u32 {
|
||||
string_array_length(&array)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn object() {
|
||||
test_macro_becomes!(
|
||||
quote! { object },
|
||||
quote! {
|
||||
struct Person {
|
||||
id: i32,
|
||||
name: Option<String>,
|
||||
}
|
||||
},
|
||||
quote! {
|
||||
#[napi_derive::napi(use_nullable = true, object)]
|
||||
struct Person {
|
||||
id: i32,
|
||||
name: Option<String>,
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn object_with_explicitly_set_use_nullable() {
|
||||
test_macro_becomes!(
|
||||
quote! { object, use_nullable = false },
|
||||
quote! {
|
||||
struct Person {
|
||||
id: i32,
|
||||
name: Option<String>,
|
||||
}
|
||||
},
|
||||
quote! {
|
||||
#[napi_derive::napi(object, use_nullable = false)]
|
||||
struct Person {
|
||||
id: i32,
|
||||
name: Option<String>,
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn macro_attr() {
|
||||
test_macro_generates!(
|
||||
quote! {
|
||||
ts_return_type = "number"
|
||||
},
|
||||
quote! {
|
||||
pub fn add_one(x: i32) -> i32 {
|
||||
x + 1
|
||||
}
|
||||
},
|
||||
quote! {
|
||||
#[napi_derive::napi(js_name = "addOne", ts_return_type = "number")]
|
||||
pub fn add_one_napi(x: i32) -> i32 {
|
||||
add_one(x)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn explicitly_specified_js_name() {
|
||||
test_macro_generates!(
|
||||
quote! {
|
||||
js_name = "add1"
|
||||
},
|
||||
quote! {
|
||||
pub fn add_one(x: i32) -> i32 {
|
||||
x + 1
|
||||
}
|
||||
},
|
||||
quote! {
|
||||
#[napi_derive::napi(js_name = "add1")]
|
||||
pub fn add_one_napi(x: i32) -> i32 {
|
||||
add_one(x)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn explicitly_specified_js_name_and_other_macro_attr() {
|
||||
test_macro_generates!(
|
||||
quote! { ts_return_type = "number", js_name = "add1" },
|
||||
quote! {
|
||||
pub fn add_one(x: i32) -> i32 {
|
||||
x + 1
|
||||
}
|
||||
},
|
||||
quote! {
|
||||
#[napi_derive::napi(ts_return_type = "number", js_name = "add1")]
|
||||
pub fn add_one_napi(x: i32) -> i32 {
|
||||
add_one(x)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
275
pnpm-lock.yaml
275
pnpm-lock.yaml
|
@ -70,8 +70,8 @@ importers:
|
|||
specifier: 1.7.0
|
||||
version: 1.7.0
|
||||
'@redocly/openapi-core':
|
||||
specifier: 1.14.0
|
||||
version: 1.14.0
|
||||
specifier: 1.15.0
|
||||
version: 1.15.0
|
||||
'@sinonjs/fake-timers':
|
||||
specifier: 11.2.2
|
||||
version: 11.2.2
|
||||
|
@ -91,8 +91,8 @@ importers:
|
|||
specifier: 0.5.0
|
||||
version: 0.5.0
|
||||
aws-sdk:
|
||||
specifier: 2.1638.0
|
||||
version: 2.1638.0
|
||||
specifier: 2.1639.0
|
||||
version: 2.1639.0
|
||||
axios:
|
||||
specifier: 1.7.2
|
||||
version: 1.7.2
|
||||
|
@ -103,8 +103,8 @@ importers:
|
|||
specifier: 2.0.5
|
||||
version: 2.0.5
|
||||
bull:
|
||||
specifier: 4.12.9
|
||||
version: 4.12.9
|
||||
specifier: 4.13.0
|
||||
version: 4.13.0
|
||||
cacheable-lookup:
|
||||
specifier: git+https://github.com/TheEssem/cacheable-lookup.git#dd2fb616366a3c68dcf321a57a67295967b204bf
|
||||
version: https://codeload.github.com/TheEssem/cacheable-lookup/tar.gz/dd2fb616366a3c68dcf321a57a67295967b204bf
|
||||
|
@ -320,7 +320,7 @@ importers:
|
|||
version: 0.2.3
|
||||
typeorm:
|
||||
specifier: 0.3.20
|
||||
version: 0.3.20(ioredis@5.4.1)(pg@8.12.0)(ts-node@10.9.2(@swc/core@1.5.27)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5))
|
||||
version: 0.3.20(ioredis@5.4.1)(pg@8.12.0)(ts-node@10.9.2(@swc/core@1.5.28)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5))
|
||||
ulid:
|
||||
specifier: 2.3.0
|
||||
version: 2.3.0
|
||||
|
@ -343,10 +343,10 @@ importers:
|
|||
devDependencies:
|
||||
'@swc/cli':
|
||||
specifier: 0.3.12
|
||||
version: 0.3.12(@swc/core@1.5.27)(chokidar@3.6.0)
|
||||
version: 0.3.12(@swc/core@1.5.28)(chokidar@3.6.0)
|
||||
'@swc/core':
|
||||
specifier: 1.5.27
|
||||
version: 1.5.27
|
||||
specifier: 1.5.28
|
||||
version: 1.5.28
|
||||
'@types/adm-zip':
|
||||
specifier: 0.5.5
|
||||
version: 0.5.5
|
||||
|
@ -496,13 +496,13 @@ importers:
|
|||
version: 2.0.0
|
||||
swc-loader:
|
||||
specifier: 0.2.6
|
||||
version: 0.2.6(@swc/core@1.5.27)(webpack@5.91.0(@swc/core@1.5.27))
|
||||
version: 0.2.6(@swc/core@1.5.28)(webpack@5.92.0(@swc/core@1.5.28))
|
||||
ts-loader:
|
||||
specifier: 9.5.1
|
||||
version: 9.5.1(typescript@5.4.5)(webpack@5.91.0(@swc/core@1.5.27))
|
||||
version: 9.5.1(typescript@5.4.5)(webpack@5.92.0(@swc/core@1.5.28))
|
||||
ts-node:
|
||||
specifier: 10.9.2
|
||||
version: 10.9.2(@swc/core@1.5.27)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5)
|
||||
version: 10.9.2(@swc/core@1.5.28)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5)
|
||||
tsconfig-paths:
|
||||
specifier: 4.2.0
|
||||
version: 4.2.0
|
||||
|
@ -513,8 +513,8 @@ importers:
|
|||
specifier: 5.4.5
|
||||
version: 5.4.5
|
||||
webpack:
|
||||
specifier: 5.91.0
|
||||
version: 5.91.0(@swc/core@1.5.27)
|
||||
specifier: 5.92.0
|
||||
version: 5.92.0(@swc/core@1.5.28)
|
||||
ws:
|
||||
specifier: 8.17.0
|
||||
version: 8.17.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)
|
||||
|
@ -592,7 +592,7 @@ importers:
|
|||
version: 9.0.8
|
||||
'@vitejs/plugin-vue':
|
||||
specifier: 5.0.5
|
||||
version: 5.0.5(vite@5.2.13(@types/node@20.14.2)(sass@1.77.4)(stylus@0.57.0)(terser@5.31.0))(vue@3.4.27(typescript@5.4.5))
|
||||
version: 5.0.5(vite@5.2.13(@types/node@20.14.2)(sass@1.77.5)(stylus@0.57.0)(terser@5.31.0))(vue@3.4.27(typescript@5.4.5))
|
||||
'@vue/runtime-core':
|
||||
specifier: 3.4.27
|
||||
version: 3.4.27
|
||||
|
@ -708,8 +708,8 @@ importers:
|
|||
specifier: 1.1.2
|
||||
version: 1.1.2
|
||||
sass:
|
||||
specifier: 1.77.4
|
||||
version: 1.77.4
|
||||
specifier: 1.77.5
|
||||
version: 1.77.5
|
||||
seedrandom:
|
||||
specifier: 3.0.5
|
||||
version: 3.0.5
|
||||
|
@ -745,10 +745,10 @@ importers:
|
|||
version: 10.0.0
|
||||
vite:
|
||||
specifier: 5.2.13
|
||||
version: 5.2.13(@types/node@20.14.2)(sass@1.77.4)(stylus@0.57.0)(terser@5.31.0)
|
||||
version: 5.2.13(@types/node@20.14.2)(sass@1.77.5)(stylus@0.57.0)(terser@5.31.0)
|
||||
vite-plugin-compression:
|
||||
specifier: 0.5.1
|
||||
version: 0.5.1(vite@5.2.13(@types/node@20.14.2)(sass@1.77.4)(stylus@0.57.0)(terser@5.31.0))
|
||||
version: 0.5.1(vite@5.2.13(@types/node@20.14.2)(sass@1.77.5)(stylus@0.57.0)(terser@5.31.0))
|
||||
vue:
|
||||
specifier: 3.4.27
|
||||
version: 3.4.27(typescript@5.4.5)
|
||||
|
@ -780,10 +780,10 @@ importers:
|
|||
devDependencies:
|
||||
'@swc/cli':
|
||||
specifier: 0.3.12
|
||||
version: 0.3.12(@swc/core@1.5.27)(chokidar@3.6.0)
|
||||
version: 0.3.12(@swc/core@1.5.28)(chokidar@3.6.0)
|
||||
'@swc/core':
|
||||
specifier: 1.5.27
|
||||
version: 1.5.27
|
||||
specifier: 1.5.28
|
||||
version: 1.5.28
|
||||
'@swc/types':
|
||||
specifier: 0.1.8
|
||||
version: 0.1.8
|
||||
|
@ -795,7 +795,7 @@ importers:
|
|||
version: 20.14.2
|
||||
jest:
|
||||
specifier: 29.7.0
|
||||
version: 29.7.0(@types/node@20.14.2)(ts-node@10.9.2(@swc/core@1.5.27)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5))
|
||||
version: 29.7.0(@types/node@20.14.2)(ts-node@10.9.2(@swc/core@1.5.28)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5))
|
||||
jest-fetch-mock:
|
||||
specifier: 3.0.3
|
||||
version: 3.0.3
|
||||
|
@ -807,10 +807,10 @@ importers:
|
|||
version: 9.3.1
|
||||
ts-jest:
|
||||
specifier: 29.1.4
|
||||
version: 29.1.4(@babel/core@7.24.6)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.6))(jest@29.7.0(@types/node@20.14.2)(ts-node@10.9.2(@swc/core@1.5.27)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5)))(typescript@5.4.5)
|
||||
version: 29.1.4(@babel/core@7.24.6)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.6))(jest@29.7.0(@types/node@20.14.2)(ts-node@10.9.2(@swc/core@1.5.28)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5)))(typescript@5.4.5)
|
||||
ts-node:
|
||||
specifier: 10.9.2
|
||||
version: 10.9.2(@swc/core@1.5.27)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5)
|
||||
version: 10.9.2(@swc/core@1.5.28)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5)
|
||||
tsd:
|
||||
specifier: 0.31.0
|
||||
version: 0.31.0
|
||||
|
@ -828,10 +828,10 @@ importers:
|
|||
version: 6.2.1
|
||||
vite:
|
||||
specifier: 5.2.13
|
||||
version: 5.2.13(@types/node@20.14.2)(sass@1.77.4)(stylus@0.57.0)(terser@5.31.0)
|
||||
version: 5.2.13(@types/node@20.14.2)(sass@1.77.5)(stylus@0.57.0)(terser@5.31.0)
|
||||
vite-plugin-compression:
|
||||
specifier: 0.5.1
|
||||
version: 0.5.1(vite@5.2.13(@types/node@20.14.2)(sass@1.77.4)(stylus@0.57.0)(terser@5.31.0))
|
||||
version: 0.5.1(vite@5.2.13(@types/node@20.14.2)(sass@1.77.5)(stylus@0.57.0)(terser@5.31.0))
|
||||
|
||||
packages:
|
||||
|
||||
|
@ -1887,11 +1887,11 @@ packages:
|
|||
'@redocly/ajv@8.11.0':
|
||||
resolution: {integrity: sha512-9GWx27t7xWhDIR02PA18nzBdLcKQRgc46xNQvjFkrYk4UOmvKhJ/dawwiX0cCOeetN5LcaaiqQbVOWYK62SGHw==}
|
||||
|
||||
'@redocly/config@0.5.0':
|
||||
resolution: {integrity: sha512-oA1ezWPT2tSV9CLk0FtZlViaFKtp+id3iAVeKBme1DdP4xUCdxEdP8umB21iLKdc6leRd5uGa+T5Ox4nHBAXWg==}
|
||||
'@redocly/config@0.6.0':
|
||||
resolution: {integrity: sha512-hNVN3eTxFj2nHYX0gGzZxxXwdE0DXWeWou1TIK3HYf0S9VKVxTxjO9EZbMB7iVUqaHkeqy4PSjlBQcEgD0Ftjg==}
|
||||
|
||||
'@redocly/openapi-core@1.14.0':
|
||||
resolution: {integrity: sha512-sraF4PGVcc6t6CaYw5raO/GWeOaa6UjcEvH/+Qm7zp+q/fbWAMwbj+1QzaNvpMspCwF+xW6TddDcnXrCDmqYVA==}
|
||||
'@redocly/openapi-core@1.15.0':
|
||||
resolution: {integrity: sha512-ac+3nn9y/dE+cgIVgIdq7eIisjZlBEJptLsCbOVLIsR2jb+O1SznXeyqy2MkTHMSs6zM/KHP4bMQy0DGmi7K0Q==}
|
||||
engines: {node: '>=14.19.0', npm: '>=7.0.0'}
|
||||
|
||||
'@rollup/plugin-alias@5.1.0':
|
||||
|
@ -2048,68 +2048,68 @@ packages:
|
|||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@swc/core-darwin-arm64@1.5.27':
|
||||
resolution: {integrity: sha512-jyoygXBcUcwUya2BI7Uvl0jwcm4kd0RBDGGkWgcFAZmwucSuLT3EsbpWhOwlL3ACT4rpnRlvh+k8nJlq3+w2Aw==}
|
||||
'@swc/core-darwin-arm64@1.5.28':
|
||||
resolution: {integrity: sha512-sP6g63ybzIdOWNDbn51tyHN8EMt7Mb4RMeHQEsXB7wQfDvzhpWB+AbfK6Gs3Q8fwP/pmWIrWW9csKOc1K2Mmkg==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@swc/core-darwin-x64@1.5.27':
|
||||
resolution: {integrity: sha512-eOC583D6b3MS9oODCcZUvAV7ajunjENAPVQL7aZaW+piERW+o4koZAiPlzFdMAUMj7UeVg+UN9sBBbTbJgruIA==}
|
||||
'@swc/core-darwin-x64@1.5.28':
|
||||
resolution: {integrity: sha512-Bd/agp/g7QocQG5AuorOzSC78t8OzeN+pCN/QvJj1CvPhvppjJw6e1vAbOR8vO2vvGi2pvtf3polrYQStJtSiA==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@swc/core-linux-arm-gnueabihf@1.5.27':
|
||||
resolution: {integrity: sha512-bMvX0yF7WYzn1K+s0JWJhvyA3OeZHVrdjka8eZ4LSeuLfC0ggJefo+klyeuN2szn/LYP6/3oByyrWNY8RSHB4w==}
|
||||
'@swc/core-linux-arm-gnueabihf@1.5.28':
|
||||
resolution: {integrity: sha512-Wr3TwPGIveS9/OBWm0r9VAL8wkCR0zQn46J8K01uYCmVhUNK3Muxjs0vQBZaOrGu94mqbj9OXY+gB3W7aDvGdA==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@swc/core-linux-arm64-gnu@1.5.27':
|
||||
resolution: {integrity: sha512-KlkOcSPxrCqZTm4XrT/LT1o9gmyM2T6bw/hL6IwTYRBJg+sej4rc9iSfVRFZBfNuG3EVkFQSXxik+0yVOXR93Q==}
|
||||
'@swc/core-linux-arm64-gnu@1.5.28':
|
||||
resolution: {integrity: sha512-8G1ZwVTuLgTAVTMPD+M97eU6WeiRIlGHwKZ5fiJHPBcz1xqIC7jQcEh7XBkobkYoU5OILotls3gzjRt8CMNyDQ==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@swc/core-linux-arm64-musl@1.5.27':
|
||||
resolution: {integrity: sha512-EwdTt5qykxFXJu7kS+0X0Mp/IlwO8KJ6LVNak2+N8bt1J1q/nCdg1tRDOYQ1Z/MVa1Tm+lJ664Qs1y2NY2SDTw==}
|
||||
'@swc/core-linux-arm64-musl@1.5.28':
|
||||
resolution: {integrity: sha512-0Ajdzb5Fzvz+XUbN5ESeHAz9aHHSYiQcm+vmsDi0TtPHmsalfnqEPZmnK0zPALPJPLQP2dDo4hELeDg3/c3xgA==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@swc/core-linux-x64-gnu@1.5.27':
|
||||
resolution: {integrity: sha512-RsBbxbiSNWLJ2jbAdITtv30J4eZw4O/JJ5zxYgWI54TdY7YrVsqIdzuX+ldximt+CYvO9irHm/mSr/IJY2YXrw==}
|
||||
'@swc/core-linux-x64-gnu@1.5.28':
|
||||
resolution: {integrity: sha512-ueQ9VejnQUM2Pt+vT0IAKoF4vYBWUP6n1KHGdILpoGe3LuafQrqu7RoyQ15C7/AYii7hAeNhTFdf6gLbg8cjFg==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@swc/core-linux-x64-musl@1.5.27':
|
||||
resolution: {integrity: sha512-XpRx0Kpy6JEi1WSMqUfR3k8hXLqNOkVqFcUfzvfQ4QNBX5Ek7ywh7WAxlPhCrFp+wAfNAqqUyRY1xZpLvRU51A==}
|
||||
'@swc/core-linux-x64-musl@1.5.28':
|
||||
resolution: {integrity: sha512-G5th8Mg0az8CbY4GQt9/m5hg2Y0kGIwvQBeVACuLQB6q2Y4txzdiTpjmFqUUhEvvl7Klyx1IHvNhfXs3zpt7PA==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@swc/core-win32-arm64-msvc@1.5.27':
|
||||
resolution: {integrity: sha512-pwSTUIokyIp+Ha1pur34qdYjxqL1QzhP/HM8anzsFs4yvV2LSI7c3qc4GWPNv2eQ9WiFXyo29uCEIRN6qig7wg==}
|
||||
'@swc/core-win32-arm64-msvc@1.5.28':
|
||||
resolution: {integrity: sha512-JezwCGavZ7CkNXx4yInI4kpb71L0zxzxA9BFlmnsGKEEjVQcKc3hFpmIzfFVs+eotlBUwDNb0+Yo9m6Cb7lllA==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@swc/core-win32-ia32-msvc@1.5.27':
|
||||
resolution: {integrity: sha512-S0S6vqFscvmxPolwmpZvTRfTbYR+eGcyc0ge4x/+HcnBCm+m84rcGxmp3bBb1edNFaIV+X47BlGvvh85cJ4rkQ==}
|
||||
'@swc/core-win32-ia32-msvc@1.5.28':
|
||||
resolution: {integrity: sha512-q8tW5J4RkOkl7vYShnWS//VAb2Ngolfm9WOMaF2GRJUr2Y/Xeb/+cNjdsNOqea2BzW049D5vdP7XPmir3/zUZw==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@swc/core-win32-x64-msvc@1.5.27':
|
||||
resolution: {integrity: sha512-aem+BcNW42JPbvV6L3Jl3LLj6G80aYADzYenToYisy0Aop0XZAxL/0FbhV+xWORNFtIUKynNtaa1CK7w0UxehQ==}
|
||||
'@swc/core-win32-x64-msvc@1.5.28':
|
||||
resolution: {integrity: sha512-jap6EiB3wG1YE1hyhNr9KLPpH4PGm+5tVMfN0l7fgKtV0ikgpcEN/YF94tru+z5m2HovqYW009+Evq9dcVGmpg==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@swc/core@1.5.27':
|
||||
resolution: {integrity: sha512-HmSSCBoUSRDFAd8aEB+WILkCofIp1c2OU6ZJWu1aCt6pijwQSkA4y51CTBcdvyy/+zX1W3cic7alfdhmQxxeEQ==}
|
||||
'@swc/core@1.5.28':
|
||||
resolution: {integrity: sha512-muCdNIqOTURUgYeyyOLYE3ShL8SZO6dw6bhRm6dCvxWzCZOncPc5fB0kjcPXTML+9KJoHL7ks5xg+vsQK+v6ig==}
|
||||
engines: {node: '>=10'}
|
||||
peerDependencies:
|
||||
'@swc/helpers': '*'
|
||||
|
@ -2698,8 +2698,8 @@ packages:
|
|||
resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
acorn-import-assertions@1.9.0:
|
||||
resolution: {integrity: sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==}
|
||||
acorn-import-attributes@1.9.5:
|
||||
resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==}
|
||||
peerDependencies:
|
||||
acorn: ^8
|
||||
|
||||
|
@ -2887,8 +2887,8 @@ packages:
|
|||
resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
aws-sdk@2.1638.0:
|
||||
resolution: {integrity: sha512-/Li+eOMvJOLuYXimt3YPd6ec9Xvzh6L5KLfU5bjuJrltQqBcW7paL+PnFqSjm7zef+fPJT7h+8sqEcuRaGUmRA==}
|
||||
aws-sdk@2.1639.0:
|
||||
resolution: {integrity: sha512-3vi9ONXhROfXTjsulFurKtJ/vBjiXirhwrRY6C7QRJyI/+m9lphtBivSYynnu7q2saAqC9ArlkEWQLRFUPy+Zg==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
|
||||
axios@0.24.0:
|
||||
|
@ -3045,8 +3045,8 @@ packages:
|
|||
builtins@5.1.0:
|
||||
resolution: {integrity: sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg==}
|
||||
|
||||
bull@4.12.9:
|
||||
resolution: {integrity: sha512-rqka/O9ZBfrKgI4fanhN6XW0AJ9WYRakjHlCJPjoHyh79xIvEjyU8hvs/CCeRdrbU6zSw8UNfDOjCUaQO1MTuQ==}
|
||||
bull@4.13.0:
|
||||
resolution: {integrity: sha512-XAAhHeXtW+luEYuid3shGv25ErmsegrVXMukbP7AqNUgRgiTnRnIGdjPyzmHu3/Tjm6jNdODqLHJ12t07fyUrQ==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
busboy@1.6.0:
|
||||
|
@ -3878,6 +3878,10 @@ packages:
|
|||
resolution: {integrity: sha512-4U5pNsuDl0EhuZpq46M5xPslstkviJuhrdobaRDBk2Jy2KO37FDAJl4lb2KlNabxT0m4MTK2UHNrsAcphE8nyw==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
|
||||
enhanced-resolve@5.17.0:
|
||||
resolution: {integrity: sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
|
||||
entities@1.1.2:
|
||||
resolution: {integrity: sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==}
|
||||
|
||||
|
@ -6649,8 +6653,8 @@ packages:
|
|||
sanitize-html@2.13.0:
|
||||
resolution: {integrity: sha512-Xff91Z+4Mz5QiNSLdLWwjgBDm5b1RU6xBT0+12rapjiaR7SwfRdjw8f+6Rir2MXKLrDicRFHdb51hGOAxmsUIA==}
|
||||
|
||||
sass@1.77.4:
|
||||
resolution: {integrity: sha512-vcF3Ckow6g939GMA4PeU7b2K/9FALXk2KF9J87txdHzXbUF9XRQRwSxcAs/fGaTnJeBFd7UoV22j3lzMLdM0Pw==}
|
||||
sass@1.77.5:
|
||||
resolution: {integrity: sha512-oDfX1mukIlxacPdQqNb6mV2tVCrnE+P3nVYioy72V5tlk56CPNcO4TCuFcaCRKKfJ1M3lH95CleRS+dVKL2qMg==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
hasBin: true
|
||||
|
||||
|
@ -7566,8 +7570,8 @@ packages:
|
|||
resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
|
||||
webpack@5.91.0:
|
||||
resolution: {integrity: sha512-rzVwlLeBWHJbmgTC/8TvAcu5vpJNII+MelQpylD4jNERPwpBJOE2lEcko1zJX3QJeLjTTAnQxn/OJ8bjDzVQaw==}
|
||||
webpack@5.92.0:
|
||||
resolution: {integrity: sha512-Bsw2X39MYIgxouNATyVpCNVWBCuUwDgWtN78g6lSdPJRLaQ/PUVm/oXcaRAyY/sMFoKFQrsPeqvTizWtq7QPCA==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
|
@ -8595,7 +8599,7 @@ snapshots:
|
|||
jest-util: 29.7.0
|
||||
slash: 3.0.0
|
||||
|
||||
'@jest/core@29.7.0(ts-node@10.9.2(@swc/core@1.5.27)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5))':
|
||||
'@jest/core@29.7.0(ts-node@10.9.2(@swc/core@1.5.28)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5))':
|
||||
dependencies:
|
||||
'@jest/console': 29.7.0
|
||||
'@jest/reporters': 29.7.0
|
||||
|
@ -8609,7 +8613,7 @@ snapshots:
|
|||
exit: 0.1.2
|
||||
graceful-fs: 4.2.11
|
||||
jest-changed-files: 29.7.0
|
||||
jest-config: 29.7.0(@types/node@20.14.2)(ts-node@10.9.2(@swc/core@1.5.27)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5))
|
||||
jest-config: 29.7.0(@types/node@20.14.2)(ts-node@10.9.2(@swc/core@1.5.28)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5))
|
||||
jest-haste-map: 29.7.0
|
||||
jest-message-util: 29.7.0
|
||||
jest-regex-util: 29.6.3
|
||||
|
@ -8949,12 +8953,12 @@ snapshots:
|
|||
require-from-string: 2.0.2
|
||||
uri-js: 4.4.1
|
||||
|
||||
'@redocly/config@0.5.0': {}
|
||||
'@redocly/config@0.6.0': {}
|
||||
|
||||
'@redocly/openapi-core@1.14.0':
|
||||
'@redocly/openapi-core@1.15.0':
|
||||
dependencies:
|
||||
'@redocly/ajv': 8.11.0
|
||||
'@redocly/config': 0.5.0
|
||||
'@redocly/config': 0.6.0
|
||||
colorette: 1.4.0
|
||||
js-levenshtein: 1.1.6
|
||||
js-yaml: 4.1.0
|
||||
|
@ -9058,10 +9062,10 @@ snapshots:
|
|||
|
||||
'@sqltools/formatter@1.2.5': {}
|
||||
|
||||
'@swc/cli@0.3.12(@swc/core@1.5.27)(chokidar@3.6.0)':
|
||||
'@swc/cli@0.3.12(@swc/core@1.5.28)(chokidar@3.6.0)':
|
||||
dependencies:
|
||||
'@mole-inc/bin-wrapper': 8.0.1
|
||||
'@swc/core': 1.5.27
|
||||
'@swc/core': 1.5.28
|
||||
'@swc/counter': 0.1.3
|
||||
commander: 8.3.0
|
||||
fast-glob: 3.3.2
|
||||
|
@ -9078,51 +9082,51 @@ snapshots:
|
|||
'@swc/wasm': 1.2.130
|
||||
optional: true
|
||||
|
||||
'@swc/core-darwin-arm64@1.5.27':
|
||||
'@swc/core-darwin-arm64@1.5.28':
|
||||
optional: true
|
||||
|
||||
'@swc/core-darwin-x64@1.5.27':
|
||||
'@swc/core-darwin-x64@1.5.28':
|
||||
optional: true
|
||||
|
||||
'@swc/core-linux-arm-gnueabihf@1.5.27':
|
||||
'@swc/core-linux-arm-gnueabihf@1.5.28':
|
||||
optional: true
|
||||
|
||||
'@swc/core-linux-arm64-gnu@1.5.27':
|
||||
'@swc/core-linux-arm64-gnu@1.5.28':
|
||||
optional: true
|
||||
|
||||
'@swc/core-linux-arm64-musl@1.5.27':
|
||||
'@swc/core-linux-arm64-musl@1.5.28':
|
||||
optional: true
|
||||
|
||||
'@swc/core-linux-x64-gnu@1.5.27':
|
||||
'@swc/core-linux-x64-gnu@1.5.28':
|
||||
optional: true
|
||||
|
||||
'@swc/core-linux-x64-musl@1.5.27':
|
||||
'@swc/core-linux-x64-musl@1.5.28':
|
||||
optional: true
|
||||
|
||||
'@swc/core-win32-arm64-msvc@1.5.27':
|
||||
'@swc/core-win32-arm64-msvc@1.5.28':
|
||||
optional: true
|
||||
|
||||
'@swc/core-win32-ia32-msvc@1.5.27':
|
||||
'@swc/core-win32-ia32-msvc@1.5.28':
|
||||
optional: true
|
||||
|
||||
'@swc/core-win32-x64-msvc@1.5.27':
|
||||
'@swc/core-win32-x64-msvc@1.5.28':
|
||||
optional: true
|
||||
|
||||
'@swc/core@1.5.27':
|
||||
'@swc/core@1.5.28':
|
||||
dependencies:
|
||||
'@swc/counter': 0.1.3
|
||||
'@swc/types': 0.1.8
|
||||
optionalDependencies:
|
||||
'@swc/core-darwin-arm64': 1.5.27
|
||||
'@swc/core-darwin-x64': 1.5.27
|
||||
'@swc/core-linux-arm-gnueabihf': 1.5.27
|
||||
'@swc/core-linux-arm64-gnu': 1.5.27
|
||||
'@swc/core-linux-arm64-musl': 1.5.27
|
||||
'@swc/core-linux-x64-gnu': 1.5.27
|
||||
'@swc/core-linux-x64-musl': 1.5.27
|
||||
'@swc/core-win32-arm64-msvc': 1.5.27
|
||||
'@swc/core-win32-ia32-msvc': 1.5.27
|
||||
'@swc/core-win32-x64-msvc': 1.5.27
|
||||
'@swc/core-darwin-arm64': 1.5.28
|
||||
'@swc/core-darwin-x64': 1.5.28
|
||||
'@swc/core-linux-arm-gnueabihf': 1.5.28
|
||||
'@swc/core-linux-arm64-gnu': 1.5.28
|
||||
'@swc/core-linux-arm64-musl': 1.5.28
|
||||
'@swc/core-linux-x64-gnu': 1.5.28
|
||||
'@swc/core-linux-x64-musl': 1.5.28
|
||||
'@swc/core-win32-arm64-msvc': 1.5.28
|
||||
'@swc/core-win32-ia32-msvc': 1.5.28
|
||||
'@swc/core-win32-x64-msvc': 1.5.28
|
||||
|
||||
'@swc/counter@0.1.3': {}
|
||||
|
||||
|
@ -9679,9 +9683,9 @@ snapshots:
|
|||
'@typescript-eslint/types': 6.21.0
|
||||
eslint-visitor-keys: 3.4.3
|
||||
|
||||
'@vitejs/plugin-vue@5.0.5(vite@5.2.13(@types/node@20.14.2)(sass@1.77.4)(stylus@0.57.0)(terser@5.31.0))(vue@3.4.27(typescript@5.4.5))':
|
||||
'@vitejs/plugin-vue@5.0.5(vite@5.2.13(@types/node@20.14.2)(sass@1.77.5)(stylus@0.57.0)(terser@5.31.0))(vue@3.4.27(typescript@5.4.5))':
|
||||
dependencies:
|
||||
vite: 5.2.13(@types/node@20.14.2)(sass@1.77.4)(stylus@0.57.0)(terser@5.31.0)
|
||||
vite: 5.2.13(@types/node@20.14.2)(sass@1.77.5)(stylus@0.57.0)(terser@5.31.0)
|
||||
vue: 3.4.27(typescript@5.4.5)
|
||||
|
||||
'@volar/language-core@2.3.0':
|
||||
|
@ -9862,7 +9866,7 @@ snapshots:
|
|||
mime-types: 2.1.35
|
||||
negotiator: 0.6.3
|
||||
|
||||
acorn-import-assertions@1.9.0(acorn@8.11.3):
|
||||
acorn-import-attributes@1.9.5(acorn@8.11.3):
|
||||
dependencies:
|
||||
acorn: 8.11.3
|
||||
|
||||
|
@ -10051,7 +10055,7 @@ snapshots:
|
|||
dependencies:
|
||||
possible-typed-array-names: 1.0.0
|
||||
|
||||
aws-sdk@2.1638.0:
|
||||
aws-sdk@2.1639.0:
|
||||
dependencies:
|
||||
buffer: 4.9.2
|
||||
events: 1.1.1
|
||||
|
@ -10243,7 +10247,7 @@ snapshots:
|
|||
buffer@4.9.2:
|
||||
dependencies:
|
||||
base64-js: 1.5.1
|
||||
ieee754: 1.1.13
|
||||
ieee754: 1.2.1
|
||||
isarray: 1.0.0
|
||||
|
||||
buffer@5.7.1:
|
||||
|
@ -10266,7 +10270,7 @@ snapshots:
|
|||
dependencies:
|
||||
semver: 7.6.2
|
||||
|
||||
bull@4.12.9:
|
||||
bull@4.13.0:
|
||||
dependencies:
|
||||
cron-parser: 4.9.0
|
||||
get-port: 5.1.1
|
||||
|
@ -10634,13 +10638,13 @@ snapshots:
|
|||
crc-32: 1.2.2
|
||||
readable-stream: 4.5.2
|
||||
|
||||
create-jest@29.7.0(@types/node@20.14.2)(ts-node@10.9.2(@swc/core@1.5.27)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5)):
|
||||
create-jest@29.7.0(@types/node@20.14.2)(ts-node@10.9.2(@swc/core@1.5.28)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5)):
|
||||
dependencies:
|
||||
'@jest/types': 29.6.3
|
||||
chalk: 4.1.2
|
||||
exit: 0.1.2
|
||||
graceful-fs: 4.2.11
|
||||
jest-config: 29.7.0(@types/node@20.14.2)(ts-node@10.9.2(@swc/core@1.5.27)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5))
|
||||
jest-config: 29.7.0(@types/node@20.14.2)(ts-node@10.9.2(@swc/core@1.5.28)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5))
|
||||
jest-util: 29.7.0
|
||||
prompts: 2.4.2
|
||||
transitivePeerDependencies:
|
||||
|
@ -10996,6 +11000,11 @@ snapshots:
|
|||
graceful-fs: 4.2.11
|
||||
tapable: 2.2.1
|
||||
|
||||
enhanced-resolve@5.17.0:
|
||||
dependencies:
|
||||
graceful-fs: 4.2.11
|
||||
tapable: 2.2.1
|
||||
|
||||
entities@1.1.2: {}
|
||||
|
||||
entities@2.2.0: {}
|
||||
|
@ -12474,16 +12483,16 @@ snapshots:
|
|||
- babel-plugin-macros
|
||||
- supports-color
|
||||
|
||||
jest-cli@29.7.0(@types/node@20.14.2)(ts-node@10.9.2(@swc/core@1.5.27)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5)):
|
||||
jest-cli@29.7.0(@types/node@20.14.2)(ts-node@10.9.2(@swc/core@1.5.28)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5)):
|
||||
dependencies:
|
||||
'@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.5.27)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5))
|
||||
'@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.5.28)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5))
|
||||
'@jest/test-result': 29.7.0
|
||||
'@jest/types': 29.6.3
|
||||
chalk: 4.1.2
|
||||
create-jest: 29.7.0(@types/node@20.14.2)(ts-node@10.9.2(@swc/core@1.5.27)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5))
|
||||
create-jest: 29.7.0(@types/node@20.14.2)(ts-node@10.9.2(@swc/core@1.5.28)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5))
|
||||
exit: 0.1.2
|
||||
import-local: 3.1.0
|
||||
jest-config: 29.7.0(@types/node@20.14.2)(ts-node@10.9.2(@swc/core@1.5.27)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5))
|
||||
jest-config: 29.7.0(@types/node@20.14.2)(ts-node@10.9.2(@swc/core@1.5.28)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5))
|
||||
jest-util: 29.7.0
|
||||
jest-validate: 29.7.0
|
||||
yargs: 17.7.2
|
||||
|
@ -12493,7 +12502,7 @@ snapshots:
|
|||
- supports-color
|
||||
- ts-node
|
||||
|
||||
jest-config@29.7.0(@types/node@20.14.2)(ts-node@10.9.2(@swc/core@1.5.27)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5)):
|
||||
jest-config@29.7.0(@types/node@20.14.2)(ts-node@10.9.2(@swc/core@1.5.28)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5)):
|
||||
dependencies:
|
||||
'@babel/core': 7.24.6
|
||||
'@jest/test-sequencer': 29.7.0
|
||||
|
@ -12519,7 +12528,7 @@ snapshots:
|
|||
strip-json-comments: 3.1.1
|
||||
optionalDependencies:
|
||||
'@types/node': 20.14.2
|
||||
ts-node: 10.9.2(@swc/core@1.5.27)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5)
|
||||
ts-node: 10.9.2(@swc/core@1.5.28)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5)
|
||||
transitivePeerDependencies:
|
||||
- babel-plugin-macros
|
||||
- supports-color
|
||||
|
@ -12757,12 +12766,12 @@ snapshots:
|
|||
merge-stream: 2.0.0
|
||||
supports-color: 8.1.1
|
||||
|
||||
jest@29.7.0(@types/node@20.14.2)(ts-node@10.9.2(@swc/core@1.5.27)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5)):
|
||||
jest@29.7.0(@types/node@20.14.2)(ts-node@10.9.2(@swc/core@1.5.28)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5)):
|
||||
dependencies:
|
||||
'@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.5.27)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5))
|
||||
'@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.5.28)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5))
|
||||
'@jest/types': 29.6.3
|
||||
import-local: 3.1.0
|
||||
jest-cli: 29.7.0(@types/node@20.14.2)(ts-node@10.9.2(@swc/core@1.5.27)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5))
|
||||
jest-cli: 29.7.0(@types/node@20.14.2)(ts-node@10.9.2(@swc/core@1.5.28)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5))
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
- babel-plugin-macros
|
||||
|
@ -14347,7 +14356,7 @@ snapshots:
|
|||
parse-srcset: 1.0.2
|
||||
postcss: 8.4.38
|
||||
|
||||
sass@1.77.4:
|
||||
sass@1.77.5:
|
||||
dependencies:
|
||||
chokidar: 3.6.0
|
||||
immutable: 4.3.6
|
||||
|
@ -14711,11 +14720,11 @@ snapshots:
|
|||
|
||||
supports-preserve-symlinks-flag@1.0.0: {}
|
||||
|
||||
swc-loader@0.2.6(@swc/core@1.5.27)(webpack@5.91.0(@swc/core@1.5.27)):
|
||||
swc-loader@0.2.6(@swc/core@1.5.28)(webpack@5.92.0(@swc/core@1.5.28)):
|
||||
dependencies:
|
||||
'@swc/core': 1.5.27
|
||||
'@swc/core': 1.5.28
|
||||
'@swc/counter': 0.1.3
|
||||
webpack: 5.91.0(@swc/core@1.5.27)
|
||||
webpack: 5.92.0(@swc/core@1.5.28)
|
||||
|
||||
swiper@11.1.4: {}
|
||||
|
||||
|
@ -14756,16 +14765,16 @@ snapshots:
|
|||
fast-fifo: 1.3.2
|
||||
streamx: 2.16.1
|
||||
|
||||
terser-webpack-plugin@5.3.10(@swc/core@1.5.27)(webpack@5.91.0(@swc/core@1.5.27)):
|
||||
terser-webpack-plugin@5.3.10(@swc/core@1.5.28)(webpack@5.92.0(@swc/core@1.5.28)):
|
||||
dependencies:
|
||||
'@jridgewell/trace-mapping': 0.3.25
|
||||
jest-worker: 27.5.1
|
||||
schema-utils: 3.3.0
|
||||
serialize-javascript: 6.0.2
|
||||
terser: 5.31.0
|
||||
webpack: 5.91.0(@swc/core@1.5.27)
|
||||
webpack: 5.92.0(@swc/core@1.5.28)
|
||||
optionalDependencies:
|
||||
'@swc/core': 1.5.27
|
||||
'@swc/core': 1.5.28
|
||||
|
||||
terser@5.31.0:
|
||||
dependencies:
|
||||
|
@ -14868,11 +14877,11 @@ snapshots:
|
|||
dependencies:
|
||||
typescript: 5.4.5
|
||||
|
||||
ts-jest@29.1.4(@babel/core@7.24.6)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.6))(jest@29.7.0(@types/node@20.14.2)(ts-node@10.9.2(@swc/core@1.5.27)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5)))(typescript@5.4.5):
|
||||
ts-jest@29.1.4(@babel/core@7.24.6)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.6))(jest@29.7.0(@types/node@20.14.2)(ts-node@10.9.2(@swc/core@1.5.28)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5)))(typescript@5.4.5):
|
||||
dependencies:
|
||||
bs-logger: 0.2.6
|
||||
fast-json-stable-stringify: 2.1.0
|
||||
jest: 29.7.0(@types/node@20.14.2)(ts-node@10.9.2(@swc/core@1.5.27)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5))
|
||||
jest: 29.7.0(@types/node@20.14.2)(ts-node@10.9.2(@swc/core@1.5.28)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5))
|
||||
jest-util: 29.7.0
|
||||
json5: 2.2.3
|
||||
lodash.memoize: 4.1.2
|
||||
|
@ -14886,7 +14895,7 @@ snapshots:
|
|||
'@jest/types': 29.6.3
|
||||
babel-jest: 29.7.0(@babel/core@7.24.6)
|
||||
|
||||
ts-loader@9.5.1(typescript@5.4.5)(webpack@5.91.0(@swc/core@1.5.27)):
|
||||
ts-loader@9.5.1(typescript@5.4.5)(webpack@5.92.0(@swc/core@1.5.28)):
|
||||
dependencies:
|
||||
chalk: 4.1.2
|
||||
enhanced-resolve: 5.16.1
|
||||
|
@ -14894,9 +14903,9 @@ snapshots:
|
|||
semver: 7.6.2
|
||||
source-map: 0.7.4
|
||||
typescript: 5.4.5
|
||||
webpack: 5.91.0(@swc/core@1.5.27)
|
||||
webpack: 5.92.0(@swc/core@1.5.28)
|
||||
|
||||
ts-node@10.9.2(@swc/core@1.5.27)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5):
|
||||
ts-node@10.9.2(@swc/core@1.5.28)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5):
|
||||
dependencies:
|
||||
'@cspotcode/source-map-support': 0.8.1
|
||||
'@tsconfig/node10': 1.0.11
|
||||
|
@ -14914,7 +14923,7 @@ snapshots:
|
|||
v8-compile-cache-lib: 3.0.1
|
||||
yn: 3.1.1
|
||||
optionalDependencies:
|
||||
'@swc/core': 1.5.27
|
||||
'@swc/core': 1.5.28
|
||||
'@swc/wasm': 1.2.130
|
||||
|
||||
tsconfig-paths@3.15.0:
|
||||
|
@ -15016,7 +15025,7 @@ snapshots:
|
|||
|
||||
typedarray@0.0.6: {}
|
||||
|
||||
typeorm@0.3.20(ioredis@5.4.1)(pg@8.12.0)(ts-node@10.9.2(@swc/core@1.5.27)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5)):
|
||||
typeorm@0.3.20(ioredis@5.4.1)(pg@8.12.0)(ts-node@10.9.2(@swc/core@1.5.28)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5)):
|
||||
dependencies:
|
||||
'@sqltools/formatter': 1.2.5
|
||||
app-root-path: 3.1.0
|
||||
|
@ -15036,7 +15045,7 @@ snapshots:
|
|||
optionalDependencies:
|
||||
ioredis: 5.4.1
|
||||
pg: 8.12.0
|
||||
ts-node: 10.9.2(@swc/core@1.5.27)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5)
|
||||
ts-node: 10.9.2(@swc/core@1.5.28)(@swc/wasm@1.2.130)(@types/node@20.14.2)(typescript@5.4.5)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
|
@ -15156,16 +15165,16 @@ snapshots:
|
|||
core-util-is: 1.0.2
|
||||
extsprintf: 1.3.0
|
||||
|
||||
vite-plugin-compression@0.5.1(vite@5.2.13(@types/node@20.14.2)(sass@1.77.4)(stylus@0.57.0)(terser@5.31.0)):
|
||||
vite-plugin-compression@0.5.1(vite@5.2.13(@types/node@20.14.2)(sass@1.77.5)(stylus@0.57.0)(terser@5.31.0)):
|
||||
dependencies:
|
||||
chalk: 4.1.2
|
||||
debug: 4.3.4(supports-color@8.1.1)
|
||||
fs-extra: 10.1.0
|
||||
vite: 5.2.13(@types/node@20.14.2)(sass@1.77.4)(stylus@0.57.0)(terser@5.31.0)
|
||||
vite: 5.2.13(@types/node@20.14.2)(sass@1.77.5)(stylus@0.57.0)(terser@5.31.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
vite@5.2.13(@types/node@20.14.2)(sass@1.77.4)(stylus@0.57.0)(terser@5.31.0):
|
||||
vite@5.2.13(@types/node@20.14.2)(sass@1.77.5)(stylus@0.57.0)(terser@5.31.0):
|
||||
dependencies:
|
||||
esbuild: 0.20.2
|
||||
postcss: 8.4.38
|
||||
|
@ -15173,7 +15182,7 @@ snapshots:
|
|||
optionalDependencies:
|
||||
'@types/node': 20.14.2
|
||||
fsevents: 2.3.3
|
||||
sass: 1.77.4
|
||||
sass: 1.77.5
|
||||
stylus: 0.57.0
|
||||
terser: 5.31.0
|
||||
|
||||
|
@ -15261,7 +15270,7 @@ snapshots:
|
|||
|
||||
webpack-sources@3.2.3: {}
|
||||
|
||||
webpack@5.91.0(@swc/core@1.5.27):
|
||||
webpack@5.92.0(@swc/core@1.5.28):
|
||||
dependencies:
|
||||
'@types/eslint-scope': 3.7.7
|
||||
'@types/estree': 1.0.5
|
||||
|
@ -15269,10 +15278,10 @@ snapshots:
|
|||
'@webassemblyjs/wasm-edit': 1.12.1
|
||||
'@webassemblyjs/wasm-parser': 1.12.1
|
||||
acorn: 8.11.3
|
||||
acorn-import-assertions: 1.9.0(acorn@8.11.3)
|
||||
acorn-import-attributes: 1.9.5(acorn@8.11.3)
|
||||
browserslist: 4.23.1
|
||||
chrome-trace-event: 1.0.4
|
||||
enhanced-resolve: 5.16.1
|
||||
enhanced-resolve: 5.17.0
|
||||
es-module-lexer: 1.5.3
|
||||
eslint-scope: 5.1.1
|
||||
events: 3.3.0
|
||||
|
@ -15284,7 +15293,7 @@ snapshots:
|
|||
neo-async: 2.6.2
|
||||
schema-utils: 3.3.0
|
||||
tapable: 2.2.1
|
||||
terser-webpack-plugin: 5.3.10(@swc/core@1.5.27)(webpack@5.91.0(@swc/core@1.5.27))
|
||||
terser-webpack-plugin: 5.3.10(@swc/core@1.5.28)(webpack@5.92.0(@swc/core@1.5.28))
|
||||
watchpack: 2.4.1
|
||||
webpack-sources: 3.2.3
|
||||
transitivePeerDependencies:
|
||||
|
@ -15403,7 +15412,7 @@ snapshots:
|
|||
|
||||
xml2js@0.6.2:
|
||||
dependencies:
|
||||
sax: 1.2.1
|
||||
sax: 1.4.1
|
||||
xmlbuilder: 11.0.1
|
||||
|
||||
xmlbuilder@11.0.1: {}
|
||||
|
|
Loading…
Reference in a new issue