Merge remote-tracking branch 'parent/main' into upstream-20231116
This commit is contained in:
commit
24371d6b2a
87 changed files with 566 additions and 347 deletions
8
.github/workflows/test-ruby.yml
vendored
8
.github/workflows/test-ruby.yml
vendored
|
@ -94,7 +94,7 @@ jobs:
|
|||
DB_HOST: localhost
|
||||
DB_USER: postgres
|
||||
DB_PASS: postgres
|
||||
DISABLE_SIMPLECOV: true
|
||||
DISABLE_SIMPLECOV: ${{ matrix.ruby-version != '.ruby-version' }}
|
||||
RAILS_ENV: test
|
||||
ALLOW_NOPAM: true
|
||||
PAM_ENABLED: true
|
||||
|
@ -138,6 +138,12 @@ jobs:
|
|||
|
||||
- run: bin/rspec
|
||||
|
||||
- name: Upload coverage reports to Codecov
|
||||
if: matrix.ruby-version == '.ruby-version'
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
files: coverage/lcov/mastodon.lcov
|
||||
|
||||
test-e2e:
|
||||
name: End to End testing
|
||||
runs-on: ubuntu-latest
|
||||
|
|
|
@ -41,23 +41,6 @@ Metrics/CyclomaticComplexity:
|
|||
Metrics/PerceivedComplexity:
|
||||
Max: 27
|
||||
|
||||
RSpec/AnyInstance:
|
||||
Exclude:
|
||||
- 'spec/controllers/activitypub/inboxes_controller_spec.rb'
|
||||
- 'spec/controllers/admin/accounts_controller_spec.rb'
|
||||
- 'spec/controllers/admin/resets_controller_spec.rb'
|
||||
- 'spec/controllers/auth/sessions_controller_spec.rb'
|
||||
- 'spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb'
|
||||
- 'spec/controllers/settings/two_factor_authentication/recovery_codes_controller_spec.rb'
|
||||
- 'spec/lib/request_spec.rb'
|
||||
- 'spec/lib/status_filter_spec.rb'
|
||||
- 'spec/models/account_spec.rb'
|
||||
- 'spec/models/setting_spec.rb'
|
||||
- 'spec/services/activitypub/process_collection_service_spec.rb'
|
||||
- 'spec/validators/follow_limit_validator_spec.rb'
|
||||
- 'spec/workers/activitypub/delivery_worker_spec.rb'
|
||||
- 'spec/workers/web/push_notification_worker_spec.rb'
|
||||
|
||||
# Configuration parameters: CountAsOne.
|
||||
RSpec/ExampleLength:
|
||||
Max: 22
|
||||
|
|
1
Gemfile
1
Gemfile
|
@ -139,6 +139,7 @@ group :test do
|
|||
|
||||
# Coverage formatter for RSpec test if DISABLE_SIMPLECOV is false
|
||||
gem 'simplecov', '~> 0.22', require: false
|
||||
gem 'simplecov-lcov', '~> 0.8', require: false
|
||||
|
||||
# Stub web requests for specs
|
||||
gem 'webmock', '~> 3.18'
|
||||
|
|
|
@ -727,6 +727,7 @@ GEM
|
|||
simplecov-html (~> 0.11)
|
||||
simplecov_json_formatter (~> 0.1)
|
||||
simplecov-html (0.12.3)
|
||||
simplecov-lcov (0.8.0)
|
||||
simplecov_json_formatter (0.1.4)
|
||||
smart_properties (1.17.0)
|
||||
sprockets (3.7.2)
|
||||
|
@ -939,6 +940,7 @@ DEPENDENCIES
|
|||
simple-navigation (~> 4.4)
|
||||
simple_form (~> 5.2)
|
||||
simplecov (~> 0.22)
|
||||
simplecov-lcov (~> 0.8)
|
||||
sprockets (~> 3.7.2)
|
||||
sprockets-rails (~> 3.4)
|
||||
stackprof
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
web: env PORT=3000 RAILS_ENV=development bundle exec puma -C config/puma.rb
|
||||
sidekiq: env PORT=3000 RAILS_ENV=development bundle exec sidekiq
|
||||
stream: env PORT=4000 yarn run start
|
||||
stream: env PORT=4000 yarn workspace @mastodon/streaming start
|
||||
webpack: bin/webpack-dev-server
|
||||
|
|
|
@ -7,6 +7,7 @@ class Api::BaseController < ApplicationController
|
|||
include RateLimitHeaders
|
||||
include AccessTokenTrackingConcern
|
||||
include ApiCachingConcern
|
||||
include Api::ContentSecurityPolicy
|
||||
|
||||
skip_before_action :require_functional!, unless: :limited_federation_mode?
|
||||
|
||||
|
@ -17,26 +18,6 @@ class Api::BaseController < ApplicationController
|
|||
|
||||
protect_from_forgery with: :null_session
|
||||
|
||||
content_security_policy do |p|
|
||||
# Set every directive that does not have a fallback
|
||||
p.default_src :none
|
||||
p.frame_ancestors :none
|
||||
p.form_action :none
|
||||
|
||||
# Disable every directive with a fallback to cut on response size
|
||||
p.base_uri false
|
||||
p.font_src false
|
||||
p.img_src false
|
||||
p.style_src false
|
||||
p.media_src false
|
||||
p.frame_src false
|
||||
p.manifest_src false
|
||||
p.connect_src false
|
||||
p.script_src false
|
||||
p.child_src false
|
||||
p.worker_src false
|
||||
end
|
||||
|
||||
rescue_from ActiveRecord::RecordInvalid, Mastodon::ValidationError do |e|
|
||||
render json: { error: e.to_s }, status: 422
|
||||
end
|
||||
|
|
|
@ -13,7 +13,7 @@ class Api::V1::Instances::DomainBlocksController < Api::V1::Instances::BaseContr
|
|||
cache_if_unauthenticated!
|
||||
end
|
||||
|
||||
render json: @domain_blocks, each_serializer: REST::DomainBlockSerializer, with_comment: (Setting.show_domain_blocks_rationale == 'all' || (Setting.show_domain_blocks_rationale == 'users' && user_signed_in?))
|
||||
render json: @domain_blocks, each_serializer: REST::DomainBlockSerializer, with_comment: show_rationale_in_response?
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -26,4 +26,16 @@ class Api::V1::Instances::DomainBlocksController < Api::V1::Instances::BaseContr
|
|||
@domain_blocks = DomainBlock.with_user_facing_limitations.by_severity
|
||||
@domain_blocks = @domain_blocks.filter { |block| !block.hidden_anonymous } unless user_signed_in?
|
||||
end
|
||||
|
||||
def show_rationale_in_response?
|
||||
always_show_rationale? || show_rationale_for_user?
|
||||
end
|
||||
|
||||
def always_show_rationale?
|
||||
Setting.show_domain_blocks_rationale == 'all'
|
||||
end
|
||||
|
||||
def show_rationale_for_user?
|
||||
Setting.show_domain_blocks_rationale == 'users' && user_signed_in?
|
||||
end
|
||||
end
|
||||
|
|
33
app/controllers/api/v1/timelines/base_controller.rb
Normal file
33
app/controllers/api/v1/timelines/base_controller.rb
Normal file
|
@ -0,0 +1,33 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Api::V1::Timelines::BaseController < Api::BaseController
|
||||
after_action :insert_pagination_headers, unless: -> { @statuses.empty? }
|
||||
|
||||
private
|
||||
|
||||
def insert_pagination_headers
|
||||
set_pagination_headers(next_path, prev_path)
|
||||
end
|
||||
|
||||
def pagination_max_id
|
||||
@statuses.last.id
|
||||
end
|
||||
|
||||
def pagination_since_id
|
||||
@statuses.first.id
|
||||
end
|
||||
|
||||
def next_path_params
|
||||
permitted_params.merge(max_id: pagination_max_id)
|
||||
end
|
||||
|
||||
def prev_path_params
|
||||
permitted_params.merge(min_id: pagination_since_id)
|
||||
end
|
||||
|
||||
def permitted_params
|
||||
params
|
||||
.slice(*self.class::PERMITTED_PARAMS)
|
||||
.permit(*self.class::PERMITTED_PARAMS)
|
||||
end
|
||||
end
|
|
@ -1,9 +1,10 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Api::V1::Timelines::HomeController < Api::BaseController
|
||||
class Api::V1::Timelines::HomeController < Api::V1::Timelines::BaseController
|
||||
before_action -> { doorkeeper_authorize! :read, :'read:statuses' }, only: [:show]
|
||||
before_action :require_user!, only: [:show]
|
||||
after_action :insert_pagination_headers, unless: -> { @statuses.empty? }
|
||||
|
||||
PERMITTED_PARAMS = %i(local limit).freeze
|
||||
|
||||
def show
|
||||
with_read_replica do
|
||||
|
@ -42,27 +43,11 @@ class Api::V1::Timelines::HomeController < Api::BaseController
|
|||
HomeFeed.new(current_account)
|
||||
end
|
||||
|
||||
def insert_pagination_headers
|
||||
set_pagination_headers(next_path, prev_path)
|
||||
end
|
||||
|
||||
def pagination_params(core_params)
|
||||
params.slice(:local, :limit).permit(:local, :limit).merge(core_params)
|
||||
end
|
||||
|
||||
def next_path
|
||||
api_v1_timelines_home_url pagination_params(max_id: pagination_max_id)
|
||||
api_v1_timelines_home_url next_path_params
|
||||
end
|
||||
|
||||
def prev_path
|
||||
api_v1_timelines_home_url pagination_params(min_id: pagination_since_id)
|
||||
end
|
||||
|
||||
def pagination_max_id
|
||||
@statuses.last.id
|
||||
end
|
||||
|
||||
def pagination_since_id
|
||||
@statuses.first.id
|
||||
api_v1_timelines_home_url prev_path_params
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Api::V1::Timelines::ListController < Api::BaseController
|
||||
class Api::V1::Timelines::ListController < Api::V1::Timelines::BaseController
|
||||
before_action -> { doorkeeper_authorize! :read, :'read:lists' }
|
||||
before_action :require_user!
|
||||
before_action :set_list
|
||||
before_action :set_statuses
|
||||
|
||||
after_action :insert_pagination_headers, unless: -> { @statuses.empty? }
|
||||
PERMITTED_PARAMS = %i(limit).freeze
|
||||
|
||||
def show
|
||||
render json: @statuses,
|
||||
|
@ -41,27 +41,11 @@ class Api::V1::Timelines::ListController < Api::BaseController
|
|||
ListFeed.new(@list)
|
||||
end
|
||||
|
||||
def insert_pagination_headers
|
||||
set_pagination_headers(next_path, prev_path)
|
||||
end
|
||||
|
||||
def pagination_params(core_params)
|
||||
params.slice(:limit).permit(:limit).merge(core_params)
|
||||
end
|
||||
|
||||
def next_path
|
||||
api_v1_timelines_list_url params[:id], pagination_params(max_id: pagination_max_id)
|
||||
api_v1_timelines_list_url params[:id], next_path_params
|
||||
end
|
||||
|
||||
def prev_path
|
||||
api_v1_timelines_list_url params[:id], pagination_params(min_id: pagination_since_id)
|
||||
end
|
||||
|
||||
def pagination_max_id
|
||||
@statuses.last.id
|
||||
end
|
||||
|
||||
def pagination_since_id
|
||||
@statuses.first.id
|
||||
api_v1_timelines_list_url params[:id], prev_path_params
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Api::V1::Timelines::PublicController < Api::BaseController
|
||||
class Api::V1::Timelines::PublicController < Api::V1::Timelines::BaseController
|
||||
before_action :require_user!, only: [:show], if: :require_auth?
|
||||
after_action :insert_pagination_headers, unless: -> { @statuses.empty? }
|
||||
|
||||
PERMITTED_PARAMS = %i(local remote limit only_media).freeze
|
||||
|
||||
def show
|
||||
cache_if_unauthenticated!
|
||||
|
@ -44,27 +45,11 @@ class Api::V1::Timelines::PublicController < Api::BaseController
|
|||
)
|
||||
end
|
||||
|
||||
def insert_pagination_headers
|
||||
set_pagination_headers(next_path, prev_path)
|
||||
end
|
||||
|
||||
def pagination_params(core_params)
|
||||
params.slice(:local, :remote, :limit, :only_media).permit(:local, :remote, :limit, :only_media).merge(core_params)
|
||||
end
|
||||
|
||||
def next_path
|
||||
api_v1_timelines_public_url pagination_params(max_id: pagination_max_id)
|
||||
api_v1_timelines_public_url next_path_params
|
||||
end
|
||||
|
||||
def prev_path
|
||||
api_v1_timelines_public_url pagination_params(min_id: pagination_since_id)
|
||||
end
|
||||
|
||||
def pagination_max_id
|
||||
@statuses.last.id
|
||||
end
|
||||
|
||||
def pagination_since_id
|
||||
@statuses.first.id
|
||||
api_v1_timelines_public_url prev_path_params
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Api::V1::Timelines::TagController < Api::BaseController
|
||||
class Api::V1::Timelines::TagController < Api::V1::Timelines::BaseController
|
||||
before_action -> { doorkeeper_authorize! :read, :'read:statuses' }, only: :show, if: :require_auth?
|
||||
before_action :load_tag
|
||||
after_action :insert_pagination_headers, unless: -> { @statuses.empty? }
|
||||
|
||||
PERMITTED_PARAMS = %i(local limit only_media).freeze
|
||||
|
||||
def show
|
||||
cache_if_unauthenticated!
|
||||
|
@ -53,27 +54,11 @@ class Api::V1::Timelines::TagController < Api::BaseController
|
|||
)
|
||||
end
|
||||
|
||||
def insert_pagination_headers
|
||||
set_pagination_headers(next_path, prev_path)
|
||||
end
|
||||
|
||||
def pagination_params(core_params)
|
||||
params.slice(:local, :limit, :only_media).permit(:local, :limit, :only_media).merge(core_params)
|
||||
end
|
||||
|
||||
def next_path
|
||||
api_v1_timelines_tag_url params[:id], pagination_params(max_id: pagination_max_id)
|
||||
api_v1_timelines_tag_url params[:id], next_path_params
|
||||
end
|
||||
|
||||
def prev_path
|
||||
api_v1_timelines_tag_url params[:id], pagination_params(min_id: pagination_since_id)
|
||||
end
|
||||
|
||||
def pagination_max_id
|
||||
@statuses.last.id
|
||||
end
|
||||
|
||||
def pagination_since_id
|
||||
@statuses.first.id
|
||||
api_v1_timelines_tag_url params[:id], prev_path_params
|
||||
end
|
||||
end
|
||||
|
|
27
app/controllers/concerns/api/content_security_policy.rb
Normal file
27
app/controllers/concerns/api/content_security_policy.rb
Normal file
|
@ -0,0 +1,27 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Api::ContentSecurityPolicy
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
content_security_policy do |policy|
|
||||
# Set every directive that does not have a fallback
|
||||
policy.default_src :none
|
||||
policy.frame_ancestors :none
|
||||
policy.form_action :none
|
||||
|
||||
# Disable every directive with a fallback to cut on response size
|
||||
policy.base_uri false
|
||||
policy.font_src false
|
||||
policy.img_src false
|
||||
policy.style_src false
|
||||
policy.media_src false
|
||||
policy.frame_src false
|
||||
policy.manifest_src false
|
||||
policy.connect_src false
|
||||
policy.script_src false
|
||||
policy.child_src false
|
||||
policy.worker_src false
|
||||
end
|
||||
end
|
||||
end
|
|
@ -219,7 +219,7 @@ class ListTimeline extends PureComponent {
|
|||
</div>
|
||||
|
||||
<div className='setting-toggle'>
|
||||
<Toggle id={`list-${id}-exclusive`} defaultChecked={isExclusive} onChange={this.onExclusiveToggle} />
|
||||
<Toggle id={`list-${id}-exclusive`} checked={isExclusive} onChange={this.onExclusiveToggle} />
|
||||
<label htmlFor={`list-${id}-exclusive`} className='setting-toggle__label'>
|
||||
<FormattedMessage id='lists.exclusive' defaultMessage='Hide these posts from home or STL' />
|
||||
</label>
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
"account.badges.group": "Groep",
|
||||
"account.block": "Blokkeer @{name}",
|
||||
"account.block_domain": "Blokkeer domein {domain}",
|
||||
"account.block_short": "Blokkeer",
|
||||
"account.blocked": "Geblokkeer",
|
||||
"account.browse_more_on_origin_server": "Verken die oorspronklike profiel",
|
||||
"account.cancel_follow_request": "Herroep volgversoek",
|
||||
|
@ -45,6 +46,7 @@
|
|||
"account.posts_with_replies": "Plasings en antwoorde",
|
||||
"account.report": "Rapporteer @{name}",
|
||||
"account.requested": "Wag op goedkeuring. Klik om volgversoek te kanselleer",
|
||||
"account.requested_follow": "{name} het versoek om jou te volg",
|
||||
"account.share": "Deel @{name} se profiel",
|
||||
"account.show_reblogs": "Wys aangestuurde plasings van @{name}",
|
||||
"account.statuses_counter": "{count, plural, one {{counter} Plaas} other {{counter} Plasings}}",
|
||||
|
@ -82,6 +84,7 @@
|
|||
"column.community": "Plaaslike tydlyn",
|
||||
"column.directory": "Blaai deur profiele",
|
||||
"column.domain_blocks": "Geblokkeerde domeine",
|
||||
"column.favourites": "Gunstelinge",
|
||||
"column.follow_requests": "Volgversoeke",
|
||||
"column.home": "Tuis",
|
||||
"column.lists": "Lyste",
|
||||
|
@ -271,6 +274,7 @@
|
|||
"privacy.unlisted.short": "Ongelys",
|
||||
"privacy_policy.last_updated": "Laaste bywerking op {date}",
|
||||
"privacy_policy.title": "Privaatheidsbeleid",
|
||||
"regeneration_indicator.sublabel": "Jou tuis-voer word voorberei!",
|
||||
"reply_indicator.cancel": "Kanselleer",
|
||||
"report.placeholder": "Type or paste additional comments",
|
||||
"report.submit": "Submit report",
|
||||
|
|
|
@ -201,7 +201,7 @@
|
|||
"disabled_account_banner.text": "Ваш уліковы запіс {disabledAccount} часова адключаны.",
|
||||
"dismissable_banner.community_timeline": "Гэта самыя апошнія допісы ад людзей, уліковыя запісы якіх размяшчаюцца на {domain}.",
|
||||
"dismissable_banner.dismiss": "Адхіліць",
|
||||
"dismissable_banner.explore_links": "Гэтыя навіны абмяркоўваюцца прама зараз на гэтым і іншых серверах дэцэнтралізаванай сеткі.",
|
||||
"dismissable_banner.explore_links": "Гэтыя навіны абмяркоўваюцца цяпер на гэтым і іншых серверах дэцэнтралізаванай сеткі.",
|
||||
"dismissable_banner.explore_statuses": "Допісы з гэтага і іншых сервераў дэцэнтралізаванай сеткі, якія набіраюць папулярнасць прама зараз.",
|
||||
"dismissable_banner.explore_tags": "Гэтыя хэштэгі зараз набіраюць папулярнасць сярод людзей на гэтым і іншых серверах дэцэнтралізаванай сеткі",
|
||||
"dismissable_banner.public_timeline": "Гэта апошнія публічныя допісы людзей з усей сеткі, за якімі сочаць карыстальнікі {domain}.",
|
||||
|
@ -482,7 +482,7 @@
|
|||
"onboarding.share.lead": "Дайце людзям ведаць, як яны могуць знайсці вас на Mastodon!",
|
||||
"onboarding.share.message": "Я {username} на #Mastodon! Сачыце за мной на {url}",
|
||||
"onboarding.share.next_steps": "Магчымыя наступныя крокі:",
|
||||
"onboarding.share.title": "Падзяліцеся сваім профілем",
|
||||
"onboarding.share.title": "Абагульце свой профіль",
|
||||
"onboarding.start.lead": "Your new Mastodon account is ready to go. Here's how you can make the most of it:",
|
||||
"onboarding.start.skip": "Want to skip right ahead?",
|
||||
"onboarding.start.title": "Вы зрабілі гэта!",
|
||||
|
@ -493,7 +493,7 @@
|
|||
"onboarding.steps.setup_profile.body": "Others are more likely to interact with you with a filled out profile.",
|
||||
"onboarding.steps.setup_profile.title": "Customize your profile",
|
||||
"onboarding.steps.share_profile.body": "Let your friends know how to find you on Mastodon!",
|
||||
"onboarding.steps.share_profile.title": "Share your profile",
|
||||
"onboarding.steps.share_profile.title": "Абагульць ваш профіль у Mastodon",
|
||||
"onboarding.tips.2fa": "<strong>Ці вы ведаеце?</strong> Вы можаце абараніць свой уліковы запіс, усталяваўшы двухфактарную аўтэнтыфікацыю ў наладах уліковага запісу. Яна працуе з любой праграмай TOTP на ваш выбар, нумар тэлефона не патрэбны!",
|
||||
"onboarding.tips.accounts_from_other_servers": "<strong>Ці вы ведаеце?</strong> Паколькі Mastodon дэцэнтралізаваны, некаторыя профілі, якія вам трапляюцца, будуць размяшчацца на іншых серверах, адрозных ад вашага. І ўсё ж вы можаце бесперашкодна ўзаемадзейнічаць з імі! Іх сервер пазначаны ў другой палове імя карыстальніка!",
|
||||
"onboarding.tips.migration": "<strong>Ці вы ведаеце?</strong> Калі вы адчуваеце, што {domain} не з'яўляецца для вас лепшым выбарам у будучыні, вы можаце перайсці на іншы сервер Mastodon, не губляючы сваіх падпісчыкаў. Вы нават можаце стварыць свой уласны сервер!",
|
||||
|
|
|
@ -222,6 +222,7 @@
|
|||
"emoji_button.search_results": "Resultats de la cerca",
|
||||
"emoji_button.symbols": "Símbols",
|
||||
"emoji_button.travel": "Viatges i llocs",
|
||||
"empty_column.account_hides_collections": "Aquest usuari ha elegit no mostrar aquesta informació",
|
||||
"empty_column.account_suspended": "Compte suspès",
|
||||
"empty_column.account_timeline": "No hi ha tuts aquí!",
|
||||
"empty_column.account_unavailable": "Perfil no disponible",
|
||||
|
|
|
@ -222,6 +222,7 @@
|
|||
"emoji_button.search_results": "Sykresultaten",
|
||||
"emoji_button.symbols": "Symboalen",
|
||||
"emoji_button.travel": "Reizgje en lokaasjes",
|
||||
"empty_column.account_hides_collections": "Dizze brûker hat derfoar keazen dizze ynformaasje net beskikber te meitsjen",
|
||||
"empty_column.account_suspended": "Account beskoattele",
|
||||
"empty_column.account_timeline": "Hjir binne gjin berjochten!",
|
||||
"empty_column.account_unavailable": "Profyl net beskikber",
|
||||
|
|
|
@ -41,6 +41,8 @@
|
|||
"account.languages": "Keisti prenumeruojamas kalbas",
|
||||
"account.locked_info": "Šios paskyros privatumo būsena nustatyta kaip užrakinta. Savininkas (-ė) rankiniu būdu peržiūri, kas gali sekti.",
|
||||
"account.media": "Medija",
|
||||
"account.mention": "Paminėti @{name}",
|
||||
"account.moved_to": "{name} nurodė, kad dabar jų nauja paskyra yra:",
|
||||
"account.mute": "Užtildyti @{name}",
|
||||
"account.muted": "Užtildytas",
|
||||
"account.posts": "Toots",
|
||||
|
@ -53,10 +55,15 @@
|
|||
"account.unfollow": "Nebesekti",
|
||||
"account.unmute_short": "Atitildyti",
|
||||
"account_note.placeholder": "Click to add a note",
|
||||
"alert.unexpected.title": "Oi!",
|
||||
"alert.unexpected.message": "Įvyko netikėta klaida.",
|
||||
"alert.unexpected.title": "Ups!",
|
||||
"announcement.announcement": "Skelbimas",
|
||||
"attachments_list.unprocessed": "(neapdorotas)",
|
||||
"audio.hide": "Slėpti garsą",
|
||||
"autosuggest_hashtag.per_week": "{count} per savaitę",
|
||||
"boost_modal.combo": "Gali spausti {combo}, kad praleisti kitą kartą",
|
||||
"bundle_column_error.copy_stacktrace": "Kopijuoti klaidos ataskaitą",
|
||||
"bundle_column_error.error.body": "Užklausos puslapio nepavyko atvaizduoti. Tai gali būti dėl mūsų kodo klaidos arba naršyklės suderinamumo problemos.",
|
||||
"bundle_column_error.error.title": "O, ne!",
|
||||
"column.domain_blocks": "Hidden domains",
|
||||
"column.lists": "Sąrašai",
|
||||
|
|
|
@ -222,6 +222,7 @@
|
|||
"emoji_button.search_results": "Rezultati iskanja",
|
||||
"emoji_button.symbols": "Simboli",
|
||||
"emoji_button.travel": "Potovanja in kraji",
|
||||
"empty_column.account_hides_collections": "Ta uporabnik se je odločil, da te informacije ne bo dal na voljo",
|
||||
"empty_column.account_suspended": "Račun je suspendiran",
|
||||
"empty_column.account_timeline": "Tukaj ni objav!",
|
||||
"empty_column.account_unavailable": "Profil ni na voljo",
|
||||
|
|
|
@ -222,6 +222,7 @@
|
|||
"emoji_button.search_results": "Rezultati pretrage",
|
||||
"emoji_button.symbols": "Simboli",
|
||||
"emoji_button.travel": "Putovanja i mesta",
|
||||
"empty_column.account_hides_collections": "Ovaj korisnik je odlučio da ove informacije ne učini dostupnim",
|
||||
"empty_column.account_suspended": "Nalog je suspendovan",
|
||||
"empty_column.account_timeline": "Nema objava ovde!",
|
||||
"empty_column.account_unavailable": "Profil je nedostupan",
|
||||
|
|
|
@ -222,6 +222,7 @@
|
|||
"emoji_button.search_results": "Резултати претраге",
|
||||
"emoji_button.symbols": "Симболи",
|
||||
"emoji_button.travel": "Путовања и места",
|
||||
"empty_column.account_hides_collections": "Овај корисник је одлучио да ове информације не учини доступним",
|
||||
"empty_column.account_suspended": "Налог је суспендован",
|
||||
"empty_column.account_timeline": "Нема објава овде!",
|
||||
"empty_column.account_unavailable": "Профил је недоступан",
|
||||
|
|
|
@ -39,7 +39,7 @@ class Tag < ApplicationRecord
|
|||
|
||||
HASHTAG_RE = %r{(?<![=/)\w])#(#{HASHTAG_NAME_PAT})}i
|
||||
HASHTAG_NAME_RE = /\A(#{HASHTAG_NAME_PAT})\z/i
|
||||
HASHTAG_INVALID_CHARS_RE = /[^[:alnum:]#{HASHTAG_SEPARATORS}]/
|
||||
HASHTAG_INVALID_CHARS_RE = /[^[:alnum:]\u0E47-\u0E4E#{HASHTAG_SEPARATORS}]/
|
||||
|
||||
validates :name, presence: true, format: { with: HASHTAG_NAME_RE }
|
||||
validates :display_name, format: { with: HASHTAG_NAME_RE }
|
||||
|
|
|
@ -53,3 +53,7 @@ af:
|
|||
position:
|
||||
elevated: kan nie hoër as jou huidige rol wees nie
|
||||
own_role: kan nie verander word met jou huidige rol nie
|
||||
webhook:
|
||||
attributes:
|
||||
events:
|
||||
invalid_permissions: geleenthede waartoe jy nie toegang het nie mag nie ingesluit word nie
|
||||
|
|
|
@ -5,7 +5,23 @@ af:
|
|||
contact_unavailable: NVT
|
||||
hosted_on: Mastodon gehuisves op %{domain}
|
||||
title: Aangaande
|
||||
accounts:
|
||||
follow: Volg
|
||||
followers:
|
||||
one: Volgeling
|
||||
other: Volgelinge
|
||||
following: Volg
|
||||
nothing_here: Daar is niks hier nie!
|
||||
posts:
|
||||
one: Plasing
|
||||
other: Plasings
|
||||
posts_tab_heading: Plasings
|
||||
admin:
|
||||
account_actions:
|
||||
action: Voer aksie uit
|
||||
title: Voer modereer aksie uit op %{acct}
|
||||
account_moderation_notes:
|
||||
create: Los nota
|
||||
accounts:
|
||||
location:
|
||||
local: Plaaslik
|
||||
|
@ -102,6 +118,7 @@ af:
|
|||
types:
|
||||
bookmarks: Boekmerke
|
||||
invites:
|
||||
invalid: Hierdie uitnodiging is nie geldig nie
|
||||
title: Nooi ander
|
||||
login_activities:
|
||||
description_html: Indien jy onbekende aktiwiteite gewaar, oorweeg dit om jou wagwoord te verander en tweefaktorverifikasie te aktiveer.
|
||||
|
|
|
@ -1418,6 +1418,7 @@ be:
|
|||
'86400': 1 дзень
|
||||
expires_in_prompt: Ніколі
|
||||
generate: Стварыць запрашальную спасылку
|
||||
invalid: Гэта запрашэнне несапраўднае
|
||||
invited_by: 'Вас запрасіў(-ла):'
|
||||
max_uses:
|
||||
few: "%{count} выкарыстанні"
|
||||
|
|
|
@ -1358,6 +1358,7 @@ ca:
|
|||
'86400': 1 dia
|
||||
expires_in_prompt: Mai
|
||||
generate: Genera
|
||||
invalid: Aquesta invitació no és vàlida
|
||||
invited_by: 'Has estat invitat per:'
|
||||
max_uses:
|
||||
one: 1 ús
|
||||
|
|
|
@ -1468,6 +1468,7 @@ cy:
|
|||
'86400': 1 diwrnod
|
||||
expires_in_prompt: Byth
|
||||
generate: Cynhyrchu dolen wahoddiad
|
||||
invalid: Nid yw'r gwahoddiad hwn yn ddilys
|
||||
invited_by: 'Cawsoch eich gwahodd gan:'
|
||||
max_uses:
|
||||
few: "%{count} defnydd"
|
||||
|
|
|
@ -1110,6 +1110,7 @@ da:
|
|||
functional: Din konto er fuldt funktionel.
|
||||
pending: Din ansøgning afventer gennemgang af vores medarbejdere. Dette kan tage noget tid. Du modtager en e-mail, hvis din ansøgning godkendes.
|
||||
redirecting_to: Din konto er inaktiv, da den pt. er omdirigerer til %{acct}.
|
||||
self_destruct: Da %{domain} er under nedlukning, vil kontoadgangen være begrænset.
|
||||
view_strikes: Se tidligere anmeldelser af din konto
|
||||
too_fast: Formularen indsendt for hurtigt, forsøg igen.
|
||||
use_security_key: Brug sikkerhedsnøgle
|
||||
|
@ -1367,6 +1368,7 @@ da:
|
|||
'86400': 1 dag
|
||||
expires_in_prompt: Aldrig
|
||||
generate: Generér invitationslink
|
||||
invalid: Denne invitation er ikke gyldig
|
||||
invited_by: 'Du blev inviteret af:'
|
||||
max_uses:
|
||||
one: 1 benyttelse
|
||||
|
@ -1579,6 +1581,9 @@ da:
|
|||
over_daily_limit: Den daglige grænse på %{limit} planlagte indlæg er nået
|
||||
over_total_limit: Grænsen på %{limit} planlagte indlæg er nået
|
||||
too_soon: Den planlagte dato skal være i fremtiden
|
||||
self_destruct:
|
||||
lead_html: Desværre lukker <strong>%{domain}</strong> permanent. Har man en konto dér, vil fortsat brug heraf ikke være mulig. Man kan dog stadig anmode om en sikkerhedskopi af sine data.
|
||||
title: Denne server er under nedlukning
|
||||
sessions:
|
||||
activity: Seneste aktivitet
|
||||
browser: Browser
|
||||
|
|
|
@ -1368,6 +1368,7 @@ de:
|
|||
'86400': 1 Tag
|
||||
expires_in_prompt: Nie
|
||||
generate: Einladungslink erstellen
|
||||
invalid: Diese Einladung ist ungültig
|
||||
invited_by: 'Du wurdest eingeladen von:'
|
||||
max_uses:
|
||||
one: Eine Verwendung
|
||||
|
|
|
@ -18,7 +18,7 @@ be:
|
|||
unconfirmed: Вы павінны пацвердзіць свой адрас электроннай пошты, перш чым працягнуць
|
||||
mailer:
|
||||
confirmation_instructions:
|
||||
action: Пацвердзіце адрас электроннай пошты
|
||||
action: Пацвердзіць адрас электроннай пошты
|
||||
action_with_app: Пацвердзіць і вярнуцца да %{app}
|
||||
explanation: Вы стварылі ўліковы запіс на %{host} з гэтым адрасам электроннай пошты. Вам спатрэбіцца ўсяго адзін клік, каб пацвердзіць яго. Калі гэта былі не вы, то проста праігнаруйце гэты ліст.
|
||||
explanation_when_pending: Вы падалі заяўку на запрашэнне на %{host} з гэтым адрасам электроннай пошты. Як толькі вы пацвердзіце свой адрас электроннай пошты, мы разгледзім вашу заяўку. Вы можаце ўвайсці, каб змяніць свае дадзеныя або выдаліць свой уліковы запіс, але вы не можаце атрымаць доступ да большасці функцый, пакуль ваш уліковы запіс не будзе зацверджаны. Калі ваша заяўка будзе адхілена, вашы даныя будуць выдалены, таму ад вас не спатрэбіцца ніякіх дадатковых дзеянняў. Калі гэта былі не вы, ігнаруйце гэты ліст
|
||||
|
|
|
@ -149,6 +149,7 @@ af:
|
|||
write:blocks: blokkeer rekeninge en domeine
|
||||
write:bookmarks: laat ’n boekmerk by plasings
|
||||
write:conversations: doof en wis gesprekke uit
|
||||
write:favourites: gunsteling plasings
|
||||
write:filters: skep filters
|
||||
write:follows: volg mense
|
||||
write:lists: skep lyste
|
||||
|
|
|
@ -1368,6 +1368,7 @@ es-AR:
|
|||
'86400': 1 día
|
||||
expires_in_prompt: Nunca
|
||||
generate: Generar enlace de invitación
|
||||
invalid: Esta invitación no es válida
|
||||
invited_by: 'Fuiste invitado por:'
|
||||
max_uses:
|
||||
one: 1 uso
|
||||
|
|
|
@ -1368,6 +1368,7 @@ es-MX:
|
|||
'86400': 1 día
|
||||
expires_in_prompt: Nunca
|
||||
generate: Generar
|
||||
invalid: Esta invitación no es válida
|
||||
invited_by: 'Fuiste invitado por:'
|
||||
max_uses:
|
||||
one: 1 uso
|
||||
|
|
|
@ -1368,6 +1368,7 @@ es:
|
|||
'86400': 1 día
|
||||
expires_in_prompt: Nunca
|
||||
generate: Generar
|
||||
invalid: Esta invitación no es válida
|
||||
invited_by: 'Fuiste invitado por:'
|
||||
max_uses:
|
||||
one: 1 uso
|
||||
|
|
|
@ -1363,6 +1363,7 @@ eu:
|
|||
'86400': Egun 1
|
||||
expires_in_prompt: Inoiz ez
|
||||
generate: Sortu
|
||||
invalid: Gonbidapen hau ez da baliozkoa
|
||||
invited_by: 'Honek gonbidatu zaitu:'
|
||||
max_uses:
|
||||
one: Erabilera 1
|
||||
|
|
|
@ -1157,6 +1157,7 @@ fa:
|
|||
'86400': ۱ روز
|
||||
expires_in_prompt: هیچ وقت
|
||||
generate: ساختن
|
||||
invalid: این دعوتنامه معتبر نیست
|
||||
invited_by: 'دعوتکنندهٔ شما:'
|
||||
max_uses:
|
||||
one: ۱ بار
|
||||
|
|
|
@ -1368,6 +1368,7 @@ fo:
|
|||
'86400': 1 dag
|
||||
expires_in_prompt: Ongantíð
|
||||
generate: Ger innbjóðingarleinki
|
||||
invalid: Henda innbjóðing er ikki gildug
|
||||
invited_by: 'Tú var bjóðað/ur av:'
|
||||
max_uses:
|
||||
one: 1 brúk
|
||||
|
|
|
@ -1368,6 +1368,7 @@ fr-QC:
|
|||
'86400': 1 jour
|
||||
expires_in_prompt: Jamais
|
||||
generate: Générer un lien d'invitation
|
||||
invalid: Cette invitation n’est pas valide
|
||||
invited_by: 'Vous avez été invité·e par :'
|
||||
max_uses:
|
||||
one: 1 utilisation
|
||||
|
|
|
@ -1368,6 +1368,7 @@ fr:
|
|||
'86400': 1 jour
|
||||
expires_in_prompt: Jamais
|
||||
generate: Générer un lien d'invitation
|
||||
invalid: Cette invitation n’est pas valide
|
||||
invited_by: 'Vous avez été invité·e par :'
|
||||
max_uses:
|
||||
one: 1 utilisation
|
||||
|
|
|
@ -1368,6 +1368,7 @@ fy:
|
|||
'86400': 1 dei
|
||||
expires_in_prompt: Nea
|
||||
generate: Utnûgingskeppeling generearje
|
||||
invalid: Dizze útnûging is net jildich
|
||||
invited_by: 'Jo binne útnûge troch:'
|
||||
max_uses:
|
||||
one: 1 kear
|
||||
|
|
|
@ -1368,6 +1368,7 @@ gl:
|
|||
'86400': 1 día
|
||||
expires_in_prompt: Nunca
|
||||
generate: Xerar
|
||||
invalid: Este convite non é válido
|
||||
invited_by: 'Convidoute:'
|
||||
max_uses:
|
||||
one: 1 uso
|
||||
|
|
|
@ -113,8 +113,8 @@ he:
|
|||
previous_strikes_description_html:
|
||||
many: לחשבון הזה יש <strong>%{count}</strong> פסילות.
|
||||
one: לחשבון הזה פסילה <strong>אחת</strong>.
|
||||
other: לחשבון הזה <strong>%{count}</strong> פסילות.
|
||||
two: לחשבון הזה <strong>%{count}</strong> פסילות.
|
||||
other: לחשבון הזה יש <strong>%{count}</strong> פסילות.
|
||||
two: לחשבון הזה יש <strong>שתי</strong> פסילות.
|
||||
promote: להעלות בדרגה
|
||||
protocol: פרטיכל
|
||||
public: פומבי
|
||||
|
@ -1418,6 +1418,7 @@ he:
|
|||
'86400': יום אחד
|
||||
expires_in_prompt: לעולם לא
|
||||
generate: יצירת קישור להזמנה
|
||||
invalid: הזמנה זו אינה תקפה
|
||||
invited_by: הוזמנת ע"י
|
||||
max_uses:
|
||||
many: "%{count} שימושים"
|
||||
|
|
|
@ -1368,6 +1368,7 @@ hu:
|
|||
'86400': 1 nap
|
||||
expires_in_prompt: Soha
|
||||
generate: Generálás
|
||||
invalid: Ez a meghívó nem érvényes
|
||||
invited_by: 'Téged meghívott:'
|
||||
max_uses:
|
||||
one: 1 használat
|
||||
|
|
|
@ -1372,6 +1372,7 @@ is:
|
|||
'86400': 1 dagur
|
||||
expires_in_prompt: Aldrei
|
||||
generate: Útbúa boðstengil
|
||||
invalid: Þetta boð er ekki gilt
|
||||
invited_by: 'Þér var boðið af:'
|
||||
max_uses:
|
||||
one: 1 afnot
|
||||
|
|
|
@ -1370,6 +1370,7 @@ it:
|
|||
'86400': 1 giorno
|
||||
expires_in_prompt: Mai
|
||||
generate: Genera
|
||||
invalid: Questo invito non è valido
|
||||
invited_by: 'Sei stato invitato da:'
|
||||
max_uses:
|
||||
one: un uso
|
||||
|
|
|
@ -1345,6 +1345,7 @@ ko:
|
|||
'86400': 1 일
|
||||
expires_in_prompt: 영원히
|
||||
generate: 초대 링크 생성하기
|
||||
invalid: 이 초대는 올바르지 않습니다
|
||||
invited_by: '당신을 초대한 사람:'
|
||||
max_uses:
|
||||
other: "%{count}회"
|
||||
|
|
|
@ -383,6 +383,7 @@ lt:
|
|||
'86400': 1 dienos
|
||||
expires_in_prompt: Niekada
|
||||
generate: Generuoti
|
||||
invalid: Šis kvietimas negalioja.
|
||||
invited_by: 'Jus pakvietė:'
|
||||
max_uses:
|
||||
few: "%{count} panaudojimai"
|
||||
|
|
|
@ -1368,6 +1368,7 @@ nl:
|
|||
'86400': 1 dag
|
||||
expires_in_prompt: Nooit
|
||||
generate: Uitnodigingslink genereren
|
||||
invalid: Deze uitnodiging is niet geldig
|
||||
invited_by: 'Jij bent uitgenodigd door:'
|
||||
max_uses:
|
||||
one: 1 keer
|
||||
|
|
|
@ -1368,6 +1368,7 @@ nn:
|
|||
'86400': 1 dag
|
||||
expires_in_prompt: Aldri
|
||||
generate: Lag innbydingslenkje
|
||||
invalid: Denne invitasjonen er ikkje gyldig
|
||||
invited_by: 'Du vart innboden av:'
|
||||
max_uses:
|
||||
one: 1 bruk
|
||||
|
|
|
@ -1368,6 +1368,7 @@
|
|||
'86400': 1 dag
|
||||
expires_in_prompt: Aldri
|
||||
generate: Generer
|
||||
invalid: Denne invitasjonen er ikke gyldig
|
||||
invited_by: 'Du ble invitert av:'
|
||||
max_uses:
|
||||
one: 1 bruk
|
||||
|
|
|
@ -1418,6 +1418,7 @@ pl:
|
|||
'86400': dobie
|
||||
expires_in_prompt: Nigdy
|
||||
generate: Wygeneruj
|
||||
invalid: Niepoprawne zaproszenie
|
||||
invited_by: 'Zostałeś(-aś) zaproszony(-a) przez:'
|
||||
max_uses:
|
||||
few: "%{count} użycia"
|
||||
|
|
|
@ -1368,6 +1368,7 @@ pt-BR:
|
|||
'86400': 1 dia
|
||||
expires_in_prompt: Nunca
|
||||
generate: Gerar convite
|
||||
invalid: Este convite não é válido
|
||||
invited_by: 'Você recebeu convite de:'
|
||||
max_uses:
|
||||
one: 1 uso
|
||||
|
|
|
@ -1368,6 +1368,7 @@ pt-PT:
|
|||
'86400': 1 dia
|
||||
expires_in_prompt: Nunca
|
||||
generate: Gerar hiperligação de convite
|
||||
invalid: Este convite não é válido
|
||||
invited_by: 'Foi convidado por:'
|
||||
max_uses:
|
||||
one: 1 uso
|
||||
|
|
|
@ -53,7 +53,7 @@ be:
|
|||
password: Не менш за 8 сімвалаў
|
||||
phrase: Параўнанне адбудзецца нягледзячы на рэгістр тэксту і папярэджанні аб змесціве допісу
|
||||
scopes: Якімі API праграм будзе дазволена карыстацца. Калі вы абярэце найвышэйшы ўзровень, не трэба абіраць асобныя.
|
||||
setting_aggregate_reblogs: Не паказваць новыя пашырэнні для допісаў, якія нядаўна пашырылі(уплывае выключна на будучыя пашырэнні)
|
||||
setting_aggregate_reblogs: Не паказваць новыя пашырэнні для допісаў, якія пашырылі нядаўна (закранае толькі нядаўнія пашырэнні)
|
||||
setting_always_send_emails: Звычайна лісты з апавяшчэннямі не будуць дасылацца, калі вы актыўна карыстаецеся Mastodon
|
||||
setting_default_sensitive: Далікатныя медыя прадвызначана схаваныя. Іх можна адкрыць адзіным клікам
|
||||
setting_display_media_default: Хаваць медыя пазначаныя як далікатныя
|
||||
|
|
|
@ -592,6 +592,8 @@ sk:
|
|||
title: Ohľadom
|
||||
appearance:
|
||||
title: Vzhľad
|
||||
content_retention:
|
||||
title: Ponechanie obsahu
|
||||
discovery:
|
||||
follow_recommendations: Odporúčania pre nasledovanie
|
||||
profile_directory: Katalóg profilov
|
||||
|
@ -616,6 +618,7 @@ sk:
|
|||
delete: Vymaž nahratý súbor
|
||||
destroyed_msg: Nahratie bolo zo stránky úspešne vymazané!
|
||||
software_updates:
|
||||
critical_update: Kritické — prosím aktualizuj rýchlo
|
||||
documentation_link: Zisti viac
|
||||
title: Dostupné aktualizácie
|
||||
types:
|
||||
|
@ -646,6 +649,10 @@ sk:
|
|||
appeal_approved: Namietnuté
|
||||
appeal_rejected: Námietka zamietnutá
|
||||
system_checks:
|
||||
elasticsearch_preset:
|
||||
action: Pozri dokumentáciu
|
||||
elasticsearch_preset_single_node:
|
||||
action: Pozri dokumentáciu
|
||||
rules_check:
|
||||
action: Spravuj serverové pravidlá
|
||||
message_html: Neurčil/a si žiadne serverové pravidlá.
|
||||
|
@ -925,6 +932,7 @@ sk:
|
|||
'86400': 1 deň
|
||||
expires_in_prompt: Nikdy
|
||||
generate: Vygeneruj
|
||||
invalid: Táto pozvánka je neplatná
|
||||
invited_by: 'Bol/a si pozvaný/á užívateľom:'
|
||||
max_uses:
|
||||
few: "%{count} využití"
|
||||
|
|
|
@ -1418,6 +1418,7 @@ sl:
|
|||
'86400': 1 dan
|
||||
expires_in_prompt: Nikoli
|
||||
generate: Ustvari
|
||||
invalid: To povabilo ni veljavno
|
||||
invited_by: 'Povabil/a vas je:'
|
||||
max_uses:
|
||||
few: "%{count} uporabe"
|
||||
|
|
|
@ -1362,6 +1362,7 @@ sq:
|
|||
'86400': 1 ditë
|
||||
expires_in_prompt: Kurrë
|
||||
generate: Prodho lidhje ftese
|
||||
invalid: Kjo ftesë s’është e vlefshme
|
||||
invited_by: 'Qetë ftuar nga:'
|
||||
max_uses:
|
||||
one: 1 përdorim
|
||||
|
|
|
@ -1393,6 +1393,7 @@ sr-Latn:
|
|||
'86400': 1 dan
|
||||
expires_in_prompt: Nikad
|
||||
generate: Generiši
|
||||
invalid: Ova pozivnica nije važeća
|
||||
invited_by: 'Pozvao Vas je:'
|
||||
max_uses:
|
||||
few: "%{count} korišćenja"
|
||||
|
|
|
@ -1393,6 +1393,7 @@ sr:
|
|||
'86400': 1 дан
|
||||
expires_in_prompt: Никад
|
||||
generate: Генериши
|
||||
invalid: Ова позивница није важећа
|
||||
invited_by: 'Позвао Вас је:'
|
||||
max_uses:
|
||||
few: "%{count} коришћења"
|
||||
|
|
|
@ -1368,6 +1368,7 @@ sv:
|
|||
'86400': 1 dag
|
||||
expires_in_prompt: Aldrig
|
||||
generate: Skapa
|
||||
invalid: Ogiltig inbjudan
|
||||
invited_by: 'Du blev inbjuden av:'
|
||||
max_uses:
|
||||
one: 1 användning
|
||||
|
|
|
@ -1343,6 +1343,7 @@ th:
|
|||
'86400': 1 วัน
|
||||
expires_in_prompt: ไม่เลย
|
||||
generate: สร้างลิงก์เชิญ
|
||||
invalid: คำเชิญนี้ไม่ถูกต้อง
|
||||
invited_by: 'คุณได้รับเชิญโดย:'
|
||||
max_uses:
|
||||
other: "%{count} การใช้งาน"
|
||||
|
|
|
@ -1368,6 +1368,7 @@ tr:
|
|||
'86400': 1 gün
|
||||
expires_in_prompt: Asla
|
||||
generate: Davet bağlantısı oluştur
|
||||
invalid: Bu davet geçerli değil
|
||||
invited_by: 'Davet edildiniz:'
|
||||
max_uses:
|
||||
one: 1 kullanım
|
||||
|
|
|
@ -1418,6 +1418,7 @@ uk:
|
|||
'86400': 1 день
|
||||
expires_in_prompt: Ніколи
|
||||
generate: Згенерувати
|
||||
invalid: Це запрошення не дійсне
|
||||
invited_by: 'Вас запросив:'
|
||||
max_uses:
|
||||
few: "%{count} використання"
|
||||
|
|
|
@ -1343,6 +1343,7 @@ zh-CN:
|
|||
'86400': 1 天后
|
||||
expires_in_prompt: 永不过期
|
||||
generate: 生成邀请链接
|
||||
invalid: 此邀请无效
|
||||
invited_by: 你的邀请人是:
|
||||
max_uses:
|
||||
other: "%{count} 次"
|
||||
|
|
|
@ -1343,6 +1343,7 @@ zh-HK:
|
|||
'86400': 1 天後
|
||||
expires_in_prompt: 永不過期
|
||||
generate: 生成邀請連結
|
||||
invalid: 此邀請無效
|
||||
invited_by: 你的邀請人是:
|
||||
max_uses:
|
||||
other: "%{count} 次"
|
||||
|
|
|
@ -1345,6 +1345,7 @@ zh-TW:
|
|||
'86400': 1 天後
|
||||
expires_in_prompt: 永不過期
|
||||
generate: 建立邀請連結
|
||||
invalid: 此邀請是無效的
|
||||
invited_by: 您的邀請人是:
|
||||
max_uses:
|
||||
other: "%{count} 則"
|
||||
|
|
27
package.json
27
package.json
|
@ -1,11 +1,13 @@
|
|||
{
|
||||
"name": "@mastodon/mastodon",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"packageManager": "yarn@4.0.2",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"workspaces": [
|
||||
"."
|
||||
".",
|
||||
"streaming"
|
||||
],
|
||||
"scripts": {
|
||||
"build:development": "cross-env RAILS_ENV=development NODE_ENV=development ./bin/webpack",
|
||||
|
@ -76,10 +78,8 @@
|
|||
"css-loader": "^5.2.7",
|
||||
"cssnano": "^6.0.1",
|
||||
"detect-passive-events": "^2.0.3",
|
||||
"dotenv": "^16.0.3",
|
||||
"emoji-mart": "npm:emoji-mart-lazyload@latest",
|
||||
"escape-html": "^1.0.3",
|
||||
"express": "^4.18.2",
|
||||
"file-loader": "^6.2.0",
|
||||
"font-awesome": "^4.7.0",
|
||||
"fuzzysort": "^2.0.4",
|
||||
|
@ -90,21 +90,15 @@
|
|||
"immutable": "^4.3.0",
|
||||
"imports-loader": "^1.2.0",
|
||||
"intl-messageformat": "^10.3.5",
|
||||
"ioredis": "^5.3.2",
|
||||
"js-yaml": "^4.1.0",
|
||||
"jsdom": "^22.1.0",
|
||||
"lodash": "^4.17.21",
|
||||
"mark-loader": "^0.1.6",
|
||||
"marky": "^1.2.5",
|
||||
"mini-css-extract-plugin": "^1.6.2",
|
||||
"mkdirp": "^3.0.1",
|
||||
"npmlog": "^7.0.1",
|
||||
"path-complete-extname": "^1.0.0",
|
||||
"pg": "^8.5.0",
|
||||
"pg-connection-string": "^2.6.0",
|
||||
"postcss": "^8.4.24",
|
||||
"postcss-loader": "^4.3.0",
|
||||
"prom-client": "^15.0.0",
|
||||
"prop-types": "^15.8.1",
|
||||
"punycode": "^2.3.0",
|
||||
"react": "^18.2.0",
|
||||
|
@ -143,7 +137,6 @@
|
|||
"tesseract.js": "^2.1.5",
|
||||
"tiny-queue": "^0.2.1",
|
||||
"twitter-text": "3.1.0",
|
||||
"uuid": "^9.0.0",
|
||||
"webpack": "^4.47.0",
|
||||
"webpack-assets-manifest": "^4.0.6",
|
||||
"webpack-bundle-analyzer": "^4.8.0",
|
||||
|
@ -155,8 +148,7 @@
|
|||
"workbox-routing": "^7.0.0",
|
||||
"workbox-strategies": "^7.0.0",
|
||||
"workbox-webpack-plugin": "^7.0.0",
|
||||
"workbox-window": "^7.0.0",
|
||||
"ws": "^8.12.1"
|
||||
"workbox-window": "^7.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@formatjs/cli": "^6.1.1",
|
||||
|
@ -165,16 +157,13 @@
|
|||
"@types/babel__core": "^7.20.1",
|
||||
"@types/emoji-mart": "^3.0.9",
|
||||
"@types/escape-html": "^1.0.2",
|
||||
"@types/express": "^4.17.17",
|
||||
"@types/hoist-non-react-statics": "^3.3.1",
|
||||
"@types/http-link-header": "^1.0.3",
|
||||
"@types/intl": "^1.2.0",
|
||||
"@types/jest": "^29.5.2",
|
||||
"@types/js-yaml": "^4.0.5",
|
||||
"@types/lodash": "^4.14.195",
|
||||
"@types/npmlog": "^4.1.4",
|
||||
"@types/object-assign": "^4.0.30",
|
||||
"@types/pg": "^8.6.6",
|
||||
"@types/prop-types": "^15.7.5",
|
||||
"@types/punycode": "^2.1.0",
|
||||
"@types/react": "^18.2.7",
|
||||
|
@ -193,7 +182,6 @@
|
|||
"@types/react-toggle": "^4.0.3",
|
||||
"@types/redux-immutable": "^4.0.3",
|
||||
"@types/requestidlecallback": "^0.3.5",
|
||||
"@types/uuid": "^9.0.0",
|
||||
"@types/webpack": "^4.41.33",
|
||||
"@types/yargs": "^17.0.24",
|
||||
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
||||
|
@ -237,16 +225,11 @@
|
|||
"optional": true
|
||||
}
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"bufferutil": "^4.0.7",
|
||||
"utf-8-validate": "^6.0.3"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*": "prettier --ignore-unknown --write",
|
||||
"Capfile|Gemfile|*.{rb,ruby,ru,rake}": "bundle exec rubocop --force-exclusion -a",
|
||||
"*.{haml}": "bundle exec haml-lint",
|
||||
"*.{js,jsx,ts,tsx}": "eslint --fix",
|
||||
"*.{css,scss}": "stylelint --fix"
|
||||
},
|
||||
"packageManager": "yarn@4.0.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ RSpec.describe ActivityPub::InboxesController do
|
|||
|
||||
before do
|
||||
allow(ActivityPub::FollowersSynchronizationWorker).to receive(:perform_async).and_return(nil)
|
||||
allow_any_instance_of(Account).to receive(:local_followers_hash).and_return('somehash')
|
||||
allow(remote_account).to receive(:local_followers_hash).and_return('somehash')
|
||||
|
||||
request.headers['Collection-Synchronization'] = synchronization_header
|
||||
post :create, body: '{}'
|
||||
|
|
|
@ -227,7 +227,8 @@ RSpec.describe Admin::AccountsController do
|
|||
let(:account) { Fabricate(:account, domain: 'example.com') }
|
||||
|
||||
before do
|
||||
allow_any_instance_of(ResolveAccountService).to receive(:call)
|
||||
service = instance_double(ResolveAccountService, call: nil)
|
||||
allow(ResolveAccountService).to receive(:new).and_return(service)
|
||||
end
|
||||
|
||||
context 'when user is admin' do
|
||||
|
|
|
@ -13,12 +13,20 @@ describe Admin::ResetsController do
|
|||
|
||||
describe 'POST #create' do
|
||||
it 'redirects to admin accounts page' do
|
||||
expect_any_instance_of(User).to receive(:send_reset_password_instructions) do |value|
|
||||
expect(value.account_id).to eq account.id
|
||||
end
|
||||
|
||||
post :create, params: { account_id: account.id }
|
||||
expect do
|
||||
post :create, params: { account_id: account.id }
|
||||
end.to change(Devise.mailer.deliveries, :size).by(2)
|
||||
|
||||
expect(Devise.mailer.deliveries).to have_attributes(
|
||||
first: have_attributes(
|
||||
to: include(account.user.email),
|
||||
subject: I18n.t('devise.mailer.password_change.subject')
|
||||
),
|
||||
last: have_attributes(
|
||||
to: include(account.user.email),
|
||||
subject: I18n.t('devise.mailer.reset_password_instructions.subject')
|
||||
)
|
||||
)
|
||||
expect(response).to redirect_to(admin_account_path(account.id))
|
||||
end
|
||||
end
|
||||
|
|
|
@ -126,7 +126,7 @@ RSpec.describe Auth::SessionsController do
|
|||
let!(:previous_login) { Fabricate(:login_activity, user: user, ip: previous_ip) }
|
||||
|
||||
before do
|
||||
allow_any_instance_of(ActionDispatch::Request).to receive(:remote_ip).and_return(current_ip)
|
||||
allow(controller.request).to receive(:remote_ip).and_return(current_ip)
|
||||
user.update(current_sign_in_at: 1.month.ago)
|
||||
post :create, params: { user: { email: user.email, password: user.password } }
|
||||
end
|
||||
|
@ -279,7 +279,9 @@ RSpec.describe Auth::SessionsController do
|
|||
|
||||
context 'when the server has an decryption error' do
|
||||
before do
|
||||
allow_any_instance_of(User).to receive(:validate_and_consume_otp!).and_raise(OpenSSL::Cipher::CipherError)
|
||||
allow(user).to receive(:validate_and_consume_otp!).with(user.current_otp).and_raise(OpenSSL::Cipher::CipherError)
|
||||
allow(User).to receive(:find_by).with(id: user.id).and_return(user)
|
||||
|
||||
post :create, params: { user: { otp_attempt: user.current_otp } }, session: { attempt_user_id: user.id, attempt_user_updated_at: user.updated_at.to_s }
|
||||
end
|
||||
|
||||
|
|
|
@ -61,6 +61,7 @@ describe Settings::TwoFactorAuthentication::ConfirmationsController do
|
|||
it 'renders page with success' do
|
||||
prepare_user_otp_generation
|
||||
prepare_user_otp_consumption
|
||||
allow(controller).to receive(:current_user).and_return(user)
|
||||
|
||||
expect do
|
||||
post :create,
|
||||
|
@ -75,30 +76,28 @@ describe Settings::TwoFactorAuthentication::ConfirmationsController do
|
|||
end
|
||||
|
||||
def prepare_user_otp_generation
|
||||
expect_any_instance_of(User).to receive(:generate_otp_backup_codes!) do |value|
|
||||
expect(value).to eq user
|
||||
otp_backup_codes
|
||||
end
|
||||
allow(user)
|
||||
.to receive(:generate_otp_backup_codes!)
|
||||
.and_return(otp_backup_codes)
|
||||
end
|
||||
|
||||
def prepare_user_otp_consumption
|
||||
expect_any_instance_of(User).to receive(:validate_and_consume_otp!) do |value, code, options|
|
||||
expect(value).to eq user
|
||||
expect(code).to eq '123456'
|
||||
expect(options).to eq({ otp_secret: 'thisisasecretforthespecofnewview' })
|
||||
true
|
||||
end
|
||||
options = { otp_secret: 'thisisasecretforthespecofnewview' }
|
||||
allow(user)
|
||||
.to receive(:validate_and_consume_otp!)
|
||||
.with('123456', options)
|
||||
.and_return(true)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when creation fails' do
|
||||
subject do
|
||||
expect_any_instance_of(User).to receive(:validate_and_consume_otp!) do |value, code, options|
|
||||
expect(value).to eq user
|
||||
expect(code).to eq '123456'
|
||||
expect(options).to eq({ otp_secret: 'thisisasecretforthespecofnewview' })
|
||||
false
|
||||
end
|
||||
options = { otp_secret: 'thisisasecretforthespecofnewview' }
|
||||
allow(user)
|
||||
.to receive(:validate_and_consume_otp!)
|
||||
.with('123456', options)
|
||||
.and_return(false)
|
||||
allow(controller).to receive(:current_user).and_return(user)
|
||||
|
||||
expect do
|
||||
post :create,
|
||||
|
|
|
@ -9,10 +9,8 @@ describe Settings::TwoFactorAuthentication::RecoveryCodesController do
|
|||
it 'updates the codes and shows them on a view when signed in' do
|
||||
user = Fabricate(:user)
|
||||
otp_backup_codes = user.generate_otp_backup_codes!
|
||||
expect_any_instance_of(User).to receive(:generate_otp_backup_codes!) do |value|
|
||||
expect(value).to eq user
|
||||
otp_backup_codes
|
||||
end
|
||||
allow(user).to receive(:generate_otp_backup_codes!).and_return(otp_backup_codes)
|
||||
allow(controller).to receive(:current_user).and_return(user)
|
||||
|
||||
sign_in user, scope: :user
|
||||
post :create, session: { challenge_passed_at: Time.now.utc }
|
||||
|
|
|
@ -64,8 +64,11 @@ describe Request do
|
|||
end
|
||||
|
||||
it 'closes underlying connection' do
|
||||
expect_any_instance_of(HTTP::Client).to receive(:close)
|
||||
allow(subject.send(:http_client)).to receive(:close)
|
||||
|
||||
expect { |block| subject.perform(&block) }.to yield_control
|
||||
|
||||
expect(subject.send(:http_client)).to have_received(:close)
|
||||
end
|
||||
|
||||
it 'returns response which implements body_with_limit' do
|
||||
|
|
|
@ -23,7 +23,8 @@ describe StatusFilter do
|
|||
|
||||
context 'when status policy does not allow show' do
|
||||
it 'filters the status' do
|
||||
allow_any_instance_of(StatusPolicy).to receive(:show?).and_return(false)
|
||||
policy = instance_double(StatusPolicy, show?: false)
|
||||
allow(StatusPolicy).to receive(:new).and_return(policy)
|
||||
|
||||
expect(filter).to be_filtered
|
||||
end
|
||||
|
@ -74,7 +75,8 @@ describe StatusFilter do
|
|||
|
||||
context 'when status policy does not allow show' do
|
||||
it 'filters the status' do
|
||||
allow_any_instance_of(StatusPolicy).to receive(:show?).and_return(false)
|
||||
policy = instance_double(StatusPolicy, show?: false)
|
||||
allow(StatusPolicy).to receive(:new).and_return(policy)
|
||||
|
||||
expect(filter).to be_filtered
|
||||
end
|
||||
|
|
|
@ -209,9 +209,13 @@ RSpec.describe Account do
|
|||
expect(account.refresh!).to be_nil
|
||||
end
|
||||
|
||||
it 'calls not ResolveAccountService#call' do
|
||||
expect_any_instance_of(ResolveAccountService).to_not receive(:call).with(acct)
|
||||
it 'does not call ResolveAccountService#call' do
|
||||
service = instance_double(ResolveAccountService, call: nil)
|
||||
allow(ResolveAccountService).to receive(:new).and_return(service)
|
||||
|
||||
account.refresh!
|
||||
|
||||
expect(service).to_not have_received(:call).with(acct)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -219,8 +223,12 @@ RSpec.describe Account do
|
|||
let(:domain) { 'example.com' }
|
||||
|
||||
it 'calls ResolveAccountService#call' do
|
||||
expect_any_instance_of(ResolveAccountService).to receive(:call).with(acct).once
|
||||
service = instance_double(ResolveAccountService, call: nil)
|
||||
allow(ResolveAccountService).to receive(:new).and_return(service)
|
||||
|
||||
account.refresh!
|
||||
|
||||
expect(service).to have_received(:call).with(acct).once
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -52,7 +52,8 @@ RSpec.describe Setting do
|
|||
before do
|
||||
allow(RailsSettings::Settings).to receive(:object).with(key).and_return(object)
|
||||
allow(described_class).to receive(:default_settings).and_return(default_settings)
|
||||
allow_any_instance_of(Settings::ScopedSettings).to receive(:thing_scoped).and_return(records)
|
||||
settings_double = instance_double(Settings::ScopedSettings, thing_scoped: records)
|
||||
allow(Settings::ScopedSettings).to receive(:new).and_return(settings_double)
|
||||
Rails.cache.delete(cache_key)
|
||||
end
|
||||
|
||||
|
@ -128,7 +129,8 @@ RSpec.describe Setting do
|
|||
|
||||
describe '.all_as_records' do
|
||||
before do
|
||||
allow_any_instance_of(Settings::ScopedSettings).to receive(:thing_scoped).and_return(records)
|
||||
settings_double = instance_double(Settings::ScopedSettings, thing_scoped: records)
|
||||
allow(Settings::ScopedSettings).to receive(:new).and_return(settings_double)
|
||||
allow(described_class).to receive(:default_settings).and_return(default_settings)
|
||||
end
|
||||
|
||||
|
|
|
@ -102,17 +102,25 @@ describe 'GET /api/v1/accounts/relationships' do
|
|||
end
|
||||
end
|
||||
|
||||
it 'returns JSON with correct data on cached requests too' do
|
||||
subject
|
||||
subject
|
||||
it 'returns JSON with correct data on previously cached requests' do
|
||||
# Initial request including multiple accounts in params
|
||||
get '/api/v1/accounts/relationships', headers: headers, params: { id: [simon.id, lewis.id] }
|
||||
expect(body_as_json.size).to eq(2)
|
||||
|
||||
# Subsequent request with different id, should override cache from first request
|
||||
get '/api/v1/accounts/relationships', headers: headers, params: { id: [simon.id] }
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
|
||||
json = body_as_json
|
||||
|
||||
expect(json).to be_a Enumerable
|
||||
expect(json.first[:following]).to be true
|
||||
expect(json.first[:showing_reblogs]).to be true
|
||||
expect(body_as_json)
|
||||
.to be_an(Enumerable)
|
||||
.and have_attributes(
|
||||
size: 1,
|
||||
first: hash_including(
|
||||
following: true,
|
||||
showing_reblogs: true
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
it 'returns JSON with correct data after change too' do
|
||||
|
|
43
spec/requests/api/v1/csp_spec.rb
Normal file
43
spec/requests/api/v1/csp_spec.rb
Normal file
|
@ -0,0 +1,43 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe 'API namespace minimal Content-Security-Policy' do
|
||||
before { stub_tests_controller }
|
||||
|
||||
after { Rails.application.reload_routes! }
|
||||
|
||||
it 'returns the correct CSP headers' do
|
||||
get '/api/v1/tests'
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(response.headers['Content-Security-Policy']).to eq(minimal_csp_headers)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def stub_tests_controller
|
||||
stub_const('Api::V1::TestsController', api_tests_controller)
|
||||
|
||||
Rails.application.routes.draw do
|
||||
get '/api/v1/tests', to: 'api/v1/tests#index'
|
||||
end
|
||||
end
|
||||
|
||||
def api_tests_controller
|
||||
Class.new(Api::BaseController) do
|
||||
def index
|
||||
head 200
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def user_signed_in? = false
|
||||
def current_user = nil
|
||||
end
|
||||
end
|
||||
|
||||
def minimal_csp_headers
|
||||
"default-src 'none'; frame-ancestors 'none'; form-action 'none'"
|
||||
end
|
||||
end
|
|
@ -76,7 +76,8 @@ RSpec.describe ActivityPub::ProcessCollectionService, type: :service do
|
|||
let(:forwarder) { Fabricate(:account, domain: 'example.com', uri: 'http://example.com/other_account') }
|
||||
|
||||
it 'does not process payload if no signature exists' do
|
||||
allow_any_instance_of(ActivityPub::LinkedDataSignature).to receive(:verify_actor!).and_return(nil)
|
||||
signature_double = instance_double(ActivityPub::LinkedDataSignature, verify_actor!: nil)
|
||||
allow(ActivityPub::LinkedDataSignature).to receive(:new).and_return(signature_double)
|
||||
allow(ActivityPub::Activity).to receive(:factory)
|
||||
|
||||
subject.call(json, forwarder)
|
||||
|
@ -87,7 +88,8 @@ RSpec.describe ActivityPub::ProcessCollectionService, type: :service do
|
|||
it 'processes payload with actor if valid signature exists' do
|
||||
payload['signature'] = { 'type' => 'RsaSignature2017' }
|
||||
|
||||
allow_any_instance_of(ActivityPub::LinkedDataSignature).to receive(:verify_actor!).and_return(actor)
|
||||
signature_double = instance_double(ActivityPub::LinkedDataSignature, verify_actor!: actor)
|
||||
allow(ActivityPub::LinkedDataSignature).to receive(:new).and_return(signature_double)
|
||||
allow(ActivityPub::Activity).to receive(:factory).with(instance_of(Hash), actor, instance_of(Hash))
|
||||
|
||||
subject.call(json, forwarder)
|
||||
|
@ -98,7 +100,8 @@ RSpec.describe ActivityPub::ProcessCollectionService, type: :service do
|
|||
it 'does not process payload if invalid signature exists' do
|
||||
payload['signature'] = { 'type' => 'RsaSignature2017' }
|
||||
|
||||
allow_any_instance_of(ActivityPub::LinkedDataSignature).to receive(:verify_actor!).and_return(nil)
|
||||
signature_double = instance_double(ActivityPub::LinkedDataSignature, verify_actor!: nil)
|
||||
allow(ActivityPub::LinkedDataSignature).to receive(:new).and_return(signature_double)
|
||||
allow(ActivityPub::Activity).to receive(:factory)
|
||||
|
||||
subject.call(json, forwarder)
|
||||
|
|
|
@ -4,13 +4,21 @@ require 'rspec/retry'
|
|||
|
||||
if ENV['DISABLE_SIMPLECOV'] != 'true'
|
||||
require 'simplecov'
|
||||
require 'simplecov-lcov'
|
||||
SimpleCov::Formatter::LcovFormatter.config.report_with_single_file = true
|
||||
SimpleCov.formatter = SimpleCov::Formatter::LcovFormatter
|
||||
SimpleCov.start 'rails' do
|
||||
enable_coverage :branch
|
||||
enable_coverage_for_eval
|
||||
|
||||
add_filter 'lib/linter'
|
||||
add_group 'Policies', 'app/policies'
|
||||
add_group 'Presenters', 'app/presenters'
|
||||
add_group 'Serializers', 'app/serializers'
|
||||
add_group 'Services', 'app/services'
|
||||
add_group 'Validators', 'app/validators'
|
||||
|
||||
add_group 'Libraries', 'lib'
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -11,7 +11,8 @@ describe ActivityPub::DeliveryWorker do
|
|||
let(:payload) { 'test' }
|
||||
|
||||
before do
|
||||
allow_any_instance_of(Account).to receive(:remote_followers_hash).with('https://example.com/api').and_return('somehash')
|
||||
allow(sender).to receive(:remote_followers_hash).with('https://example.com/api').and_return('somehash')
|
||||
allow(Account).to receive(:find).with(sender.id).and_return(sender)
|
||||
end
|
||||
|
||||
describe 'perform' do
|
||||
|
|
|
@ -23,8 +23,8 @@ describe Web::PushNotificationWorker do
|
|||
|
||||
describe 'perform' do
|
||||
before do
|
||||
allow_any_instance_of(subscription.class).to receive(:contact_email).and_return(contact_email)
|
||||
allow_any_instance_of(subscription.class).to receive(:vapid_key).and_return(vapid_key)
|
||||
allow(subscription).to receive_messages(contact_email: contact_email, vapid_key: vapid_key)
|
||||
allow(Web::PushSubscription).to receive(:find).with(subscription.id).and_return(subscription)
|
||||
allow(Webpush::Encryption).to receive(:encrypt).and_return(payload)
|
||||
allow(JWT).to receive(:encode).and_return('jwt.encoded.payload')
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
const fs = require('fs');
|
||||
const http = require('http');
|
||||
const path = require('path');
|
||||
const url = require('url');
|
||||
|
||||
const dotenv = require('dotenv');
|
||||
|
@ -17,8 +18,11 @@ const WebSocket = require('ws');
|
|||
|
||||
const environment = process.env.NODE_ENV || 'development';
|
||||
|
||||
// Correctly detect and load .env or .env.production file based on environment:
|
||||
const dotenvFile = environment === 'production' ? '.env.production' : '.env';
|
||||
|
||||
dotenv.config({
|
||||
path: environment === 'production' ? '.env.production' : '.env',
|
||||
path: path.resolve(__dirname, path.join('..', dotenvFile))
|
||||
});
|
||||
|
||||
log.level = process.env.LOG_LEVEL || 'verbose';
|
||||
|
|
39
streaming/package.json
Normal file
39
streaming/package.json
Normal file
|
@ -0,0 +1,39 @@
|
|||
{
|
||||
"name": "@mastodon/streaming",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"packageManager": "yarn@4.0.2",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"description": "Mastodon's Streaming Server",
|
||||
"private": true,
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mastodon/mastodon.git"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "node ./index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"dotenv": "^16.0.3",
|
||||
"express": "^4.18.2",
|
||||
"ioredis": "^5.3.2",
|
||||
"jsdom": "^22.1.0",
|
||||
"npmlog": "^7.0.1",
|
||||
"pg": "^8.5.0",
|
||||
"pg-connection-string": "^2.6.0",
|
||||
"prom-client": "^15.0.0",
|
||||
"uuid": "^9.0.0",
|
||||
"ws": "^8.12.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/express": "^4.17.17",
|
||||
"@types/npmlog": "^4.1.4",
|
||||
"@types/pg": "^8.6.6",
|
||||
"@types/uuid": "^9.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"bufferutil": "^4.0.7",
|
||||
"utf-8-validate": "^6.0.3"
|
||||
}
|
||||
}
|
321
yarn.lock
321
yarn.lock
|
@ -1800,6 +1800,16 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@formatjs/ecma402-abstract@npm:1.18.0":
|
||||
version: 1.18.0
|
||||
resolution: "@formatjs/ecma402-abstract@npm:1.18.0"
|
||||
dependencies:
|
||||
"@formatjs/intl-localematcher": "npm:0.5.2"
|
||||
tslib: "npm:^2.4.0"
|
||||
checksum: bbdad0aee8e48baad6bfe6b2c27caf3befe35e658b922ee2f84417a819f0bdc7e849a8c0c782db8b53f5666bf19669d2b10a1104257c08796d198c87766bfc92
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@formatjs/fast-memoize@npm:2.2.0":
|
||||
version: 2.2.0
|
||||
resolution: "@formatjs/fast-memoize@npm:2.2.0"
|
||||
|
@ -1820,6 +1830,17 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@formatjs/icu-messageformat-parser@npm:2.7.3":
|
||||
version: 2.7.3
|
||||
resolution: "@formatjs/icu-messageformat-parser@npm:2.7.3"
|
||||
dependencies:
|
||||
"@formatjs/ecma402-abstract": "npm:1.18.0"
|
||||
"@formatjs/icu-skeleton-parser": "npm:1.7.0"
|
||||
tslib: "npm:^2.4.0"
|
||||
checksum: 2a51038813e5cff7e2df767e1227373d228e907adb7268fc3744b3d82c4fa69d4aa9f6020a62de2c468cf724600e9372ac07ae43a4480ed066fe34e224e80e4a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@formatjs/icu-skeleton-parser@npm:1.6.4":
|
||||
version: 1.6.4
|
||||
resolution: "@formatjs/icu-skeleton-parser@npm:1.6.4"
|
||||
|
@ -1830,25 +1851,35 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@formatjs/intl-displaynames@npm:6.6.3":
|
||||
version: 6.6.3
|
||||
resolution: "@formatjs/intl-displaynames@npm:6.6.3"
|
||||
"@formatjs/icu-skeleton-parser@npm:1.7.0":
|
||||
version: 1.7.0
|
||||
resolution: "@formatjs/icu-skeleton-parser@npm:1.7.0"
|
||||
dependencies:
|
||||
"@formatjs/ecma402-abstract": "npm:1.17.4"
|
||||
"@formatjs/intl-localematcher": "npm:0.5.1"
|
||||
"@formatjs/ecma402-abstract": "npm:1.18.0"
|
||||
tslib: "npm:^2.4.0"
|
||||
checksum: b0520cb744a51290fbcde80860f39ed9c9df9b81beae98986e1fc089ef635f7699c750631fa42a559f3678d1dd02b14904614e70360477d18e68d3eba6592390
|
||||
checksum: 2e4db815247ddb10f7990bbb501c85b854ee951ee45143673eb91b4392b11d0a8312327adb8b624c6a2fdafab12083904630d6d22475503d025f1612da4dcaee
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@formatjs/intl-listformat@npm:7.5.2":
|
||||
version: 7.5.2
|
||||
resolution: "@formatjs/intl-listformat@npm:7.5.2"
|
||||
"@formatjs/intl-displaynames@npm:6.6.4":
|
||||
version: 6.6.4
|
||||
resolution: "@formatjs/intl-displaynames@npm:6.6.4"
|
||||
dependencies:
|
||||
"@formatjs/ecma402-abstract": "npm:1.17.4"
|
||||
"@formatjs/intl-localematcher": "npm:0.5.1"
|
||||
"@formatjs/ecma402-abstract": "npm:1.18.0"
|
||||
"@formatjs/intl-localematcher": "npm:0.5.2"
|
||||
tslib: "npm:^2.4.0"
|
||||
checksum: 54fa03da4ea45504681d6d87d72d1cac574809ce43f965fa4b845e83be3072d92324c58cec57ad386827087fb1d6ecae438d29576f30176bf52eb212e454bce2
|
||||
checksum: 009e443dd0d10776b8573d0181407d4c0d6c7a2ff537a5ea1e36413d1b08db9c21dfef272eabab8efabd01a58b64f663a30e4d584fd761df3fd68a5d23fe444b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@formatjs/intl-listformat@npm:7.5.3":
|
||||
version: 7.5.3
|
||||
resolution: "@formatjs/intl-listformat@npm:7.5.3"
|
||||
dependencies:
|
||||
"@formatjs/ecma402-abstract": "npm:1.18.0"
|
||||
"@formatjs/intl-localematcher": "npm:0.5.2"
|
||||
tslib: "npm:^2.4.0"
|
||||
checksum: de741ce84b16fed57016afbfe446ebd57cd23a046859a9353f5d455f8bc9114493bf83b9e18429268c7ce8f77bc54516a9b8190baf09fbb25c9b06cfc80101d4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
@ -1861,34 +1892,43 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@formatjs/intl-pluralrules@npm:^5.2.2":
|
||||
version: 5.2.9
|
||||
resolution: "@formatjs/intl-pluralrules@npm:5.2.9"
|
||||
"@formatjs/intl-localematcher@npm:0.5.2":
|
||||
version: 0.5.2
|
||||
resolution: "@formatjs/intl-localematcher@npm:0.5.2"
|
||||
dependencies:
|
||||
"@formatjs/ecma402-abstract": "npm:1.17.4"
|
||||
"@formatjs/intl-localematcher": "npm:0.5.1"
|
||||
tslib: "npm:^2.4.0"
|
||||
checksum: a6ca5c498ce542facacf8ce8640d4ba068f9119b758547a23614b50611eb385a46abd386ff88fa423211355ec463cf102c2c908b74f6e23a5bc9e2a23873dc29
|
||||
checksum: 4b3ae75470e3e53ffa39b2d46e65a2a4c9c4becbc0aac989b0694370e10c6687643660a045512d676509bc29b257fe5726fbb028de12f889be02c2d20b6527e6
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@formatjs/intl@npm:2.9.8":
|
||||
version: 2.9.8
|
||||
resolution: "@formatjs/intl@npm:2.9.8"
|
||||
"@formatjs/intl-pluralrules@npm:^5.2.2":
|
||||
version: 5.2.10
|
||||
resolution: "@formatjs/intl-pluralrules@npm:5.2.10"
|
||||
dependencies:
|
||||
"@formatjs/ecma402-abstract": "npm:1.17.4"
|
||||
"@formatjs/ecma402-abstract": "npm:1.18.0"
|
||||
"@formatjs/intl-localematcher": "npm:0.5.2"
|
||||
tslib: "npm:^2.4.0"
|
||||
checksum: 1050416613e80bff2c58546c80c8d52ed97847d13c90535a53d058e44969369b50e1cfdb464e9e9ef4802c934c84ea0e656c3f4e3b4d5ac7496b722c759da4cf
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@formatjs/intl@npm:2.9.9":
|
||||
version: 2.9.9
|
||||
resolution: "@formatjs/intl@npm:2.9.9"
|
||||
dependencies:
|
||||
"@formatjs/ecma402-abstract": "npm:1.18.0"
|
||||
"@formatjs/fast-memoize": "npm:2.2.0"
|
||||
"@formatjs/icu-messageformat-parser": "npm:2.7.2"
|
||||
"@formatjs/intl-displaynames": "npm:6.6.3"
|
||||
"@formatjs/intl-listformat": "npm:7.5.2"
|
||||
intl-messageformat: "npm:10.5.7"
|
||||
"@formatjs/icu-messageformat-parser": "npm:2.7.3"
|
||||
"@formatjs/intl-displaynames": "npm:6.6.4"
|
||||
"@formatjs/intl-listformat": "npm:7.5.3"
|
||||
intl-messageformat: "npm:10.5.8"
|
||||
tslib: "npm:^2.4.0"
|
||||
peerDependencies:
|
||||
typescript: 5
|
||||
peerDependenciesMeta:
|
||||
typescript:
|
||||
optional: true
|
||||
checksum: 6341f4bfb56a0e14373395b1232e1eeb8e64588a8c3d4614cd2b06f71d4e65dbd4a79e3a1c07e1b6c20c48e399ac2385977b01a559e1d2bd1a1d226e0eae3058
|
||||
checksum: b26904da605ab309535dfbbfbd403a3bb33d51d3c969c548b88fa04755be3aff60b1bddd1c453514a84048c7432271cef507ac66de32dcfa66b3f842a1ddb977
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
@ -1912,6 +1952,26 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@formatjs/ts-transformer@npm:3.13.9":
|
||||
version: 3.13.9
|
||||
resolution: "@formatjs/ts-transformer@npm:3.13.9"
|
||||
dependencies:
|
||||
"@formatjs/icu-messageformat-parser": "npm:2.7.3"
|
||||
"@types/json-stable-stringify": "npm:^1.0.32"
|
||||
"@types/node": "npm:14 || 16 || 17"
|
||||
chalk: "npm:^4.0.0"
|
||||
json-stable-stringify: "npm:^1.0.1"
|
||||
tslib: "npm:^2.4.0"
|
||||
typescript: "npm:5"
|
||||
peerDependencies:
|
||||
ts-jest: ">=27"
|
||||
peerDependenciesMeta:
|
||||
ts-jest:
|
||||
optional: true
|
||||
checksum: 4e313b967e45aae79246174c3181d31cc7cd297380d3a880a98fc0be16d76b783868712151e840ea16d22e2fbec0388b1005f688b6d4cb74ee4411b43f6d33f4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@gamestdio/websocket@npm:^0.3.2":
|
||||
version: 0.3.2
|
||||
resolution: "@gamestdio/websocket@npm:0.3.2"
|
||||
|
@ -2327,16 +2387,13 @@ __metadata:
|
|||
"@types/babel__core": "npm:^7.20.1"
|
||||
"@types/emoji-mart": "npm:^3.0.9"
|
||||
"@types/escape-html": "npm:^1.0.2"
|
||||
"@types/express": "npm:^4.17.17"
|
||||
"@types/hoist-non-react-statics": "npm:^3.3.1"
|
||||
"@types/http-link-header": "npm:^1.0.3"
|
||||
"@types/intl": "npm:^1.2.0"
|
||||
"@types/jest": "npm:^29.5.2"
|
||||
"@types/js-yaml": "npm:^4.0.5"
|
||||
"@types/lodash": "npm:^4.14.195"
|
||||
"@types/npmlog": "npm:^4.1.4"
|
||||
"@types/object-assign": "npm:^4.0.30"
|
||||
"@types/pg": "npm:^8.6.6"
|
||||
"@types/prop-types": "npm:^15.7.5"
|
||||
"@types/punycode": "npm:^2.1.0"
|
||||
"@types/react": "npm:^18.2.7"
|
||||
|
@ -2355,7 +2412,6 @@ __metadata:
|
|||
"@types/react-toggle": "npm:^4.0.3"
|
||||
"@types/redux-immutable": "npm:^4.0.3"
|
||||
"@types/requestidlecallback": "npm:^0.3.5"
|
||||
"@types/uuid": "npm:^9.0.0"
|
||||
"@types/webpack": "npm:^4.41.33"
|
||||
"@types/yargs": "npm:^17.0.24"
|
||||
"@typescript-eslint/eslint-plugin": "npm:^6.0.0"
|
||||
|
@ -2371,7 +2427,6 @@ __metadata:
|
|||
babel-plugin-preval: "npm:^5.1.0"
|
||||
babel-plugin-transform-react-remove-prop-types: "npm:^0.4.24"
|
||||
blurhash: "npm:^2.0.5"
|
||||
bufferutil: "npm:^4.0.7"
|
||||
circular-dependency-plugin: "npm:^5.2.2"
|
||||
classnames: "npm:^2.3.2"
|
||||
cocoon-js-vanilla: "npm:^1.3.0"
|
||||
|
@ -2382,7 +2437,6 @@ __metadata:
|
|||
css-loader: "npm:^5.2.7"
|
||||
cssnano: "npm:^6.0.1"
|
||||
detect-passive-events: "npm:^2.0.3"
|
||||
dotenv: "npm:^16.0.3"
|
||||
emoji-mart: "npm:emoji-mart-lazyload@latest"
|
||||
escape-html: "npm:^1.0.3"
|
||||
eslint: "npm:^8.41.0"
|
||||
|
@ -2396,7 +2450,6 @@ __metadata:
|
|||
eslint-plugin-promise: "npm:~6.1.1"
|
||||
eslint-plugin-react: "npm:~7.33.0"
|
||||
eslint-plugin-react-hooks: "npm:^4.6.0"
|
||||
express: "npm:^4.18.2"
|
||||
file-loader: "npm:^6.2.0"
|
||||
font-awesome: "npm:^4.7.0"
|
||||
fuzzysort: "npm:^2.0.4"
|
||||
|
@ -2408,25 +2461,19 @@ __metadata:
|
|||
immutable: "npm:^4.3.0"
|
||||
imports-loader: "npm:^1.2.0"
|
||||
intl-messageformat: "npm:^10.3.5"
|
||||
ioredis: "npm:^5.3.2"
|
||||
jest: "npm:^29.5.0"
|
||||
jest-environment-jsdom: "npm:^29.5.0"
|
||||
js-yaml: "npm:^4.1.0"
|
||||
jsdom: "npm:^22.1.0"
|
||||
lint-staged: "npm:^15.0.0"
|
||||
lodash: "npm:^4.17.21"
|
||||
mark-loader: "npm:^0.1.6"
|
||||
marky: "npm:^1.2.5"
|
||||
mini-css-extract-plugin: "npm:^1.6.2"
|
||||
mkdirp: "npm:^3.0.1"
|
||||
npmlog: "npm:^7.0.1"
|
||||
path-complete-extname: "npm:^1.0.0"
|
||||
pg: "npm:^8.5.0"
|
||||
pg-connection-string: "npm:^2.6.0"
|
||||
postcss: "npm:^8.4.24"
|
||||
postcss-loader: "npm:^4.3.0"
|
||||
prettier: "npm:^3.0.0"
|
||||
prom-client: "npm:^15.0.0"
|
||||
prop-types: "npm:^15.8.1"
|
||||
punycode: "npm:^2.3.0"
|
||||
react: "npm:^18.2.0"
|
||||
|
@ -2469,8 +2516,6 @@ __metadata:
|
|||
tiny-queue: "npm:^0.2.1"
|
||||
twitter-text: "npm:3.1.0"
|
||||
typescript: "npm:^5.0.4"
|
||||
utf-8-validate: "npm:^6.0.3"
|
||||
uuid: "npm:^9.0.0"
|
||||
webpack: "npm:^4.47.0"
|
||||
webpack-assets-manifest: "npm:^4.0.6"
|
||||
webpack-bundle-analyzer: "npm:^4.8.0"
|
||||
|
@ -2484,13 +2529,7 @@ __metadata:
|
|||
workbox-strategies: "npm:^7.0.0"
|
||||
workbox-webpack-plugin: "npm:^7.0.0"
|
||||
workbox-window: "npm:^7.0.0"
|
||||
ws: "npm:^8.12.1"
|
||||
yargs: "npm:^17.7.2"
|
||||
dependenciesMeta:
|
||||
bufferutil:
|
||||
optional: true
|
||||
utf-8-validate:
|
||||
optional: true
|
||||
peerDependenciesMeta:
|
||||
react:
|
||||
optional: true
|
||||
|
@ -2501,6 +2540,34 @@ __metadata:
|
|||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@mastodon/streaming@workspace:streaming":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@mastodon/streaming@workspace:streaming"
|
||||
dependencies:
|
||||
"@types/express": "npm:^4.17.17"
|
||||
"@types/npmlog": "npm:^4.1.4"
|
||||
"@types/pg": "npm:^8.6.6"
|
||||
"@types/uuid": "npm:^9.0.0"
|
||||
bufferutil: "npm:^4.0.7"
|
||||
dotenv: "npm:^16.0.3"
|
||||
express: "npm:^4.18.2"
|
||||
ioredis: "npm:^5.3.2"
|
||||
jsdom: "npm:^22.1.0"
|
||||
npmlog: "npm:^7.0.1"
|
||||
pg: "npm:^8.5.0"
|
||||
pg-connection-string: "npm:^2.6.0"
|
||||
prom-client: "npm:^15.0.0"
|
||||
utf-8-validate: "npm:^6.0.3"
|
||||
uuid: "npm:^9.0.0"
|
||||
ws: "npm:^8.12.1"
|
||||
dependenciesMeta:
|
||||
bufferutil:
|
||||
optional: true
|
||||
utf-8-validate:
|
||||
optional: true
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@material-symbols/svg-600@npm:^0.14.0":
|
||||
version: 0.14.0
|
||||
resolution: "@material-symbols/svg-600@npm:0.14.0"
|
||||
|
@ -3015,21 +3082,21 @@ __metadata:
|
|||
linkType: hard
|
||||
|
||||
"@types/body-parser@npm:*":
|
||||
version: 1.19.4
|
||||
resolution: "@types/body-parser@npm:1.19.4"
|
||||
version: 1.19.5
|
||||
resolution: "@types/body-parser@npm:1.19.5"
|
||||
dependencies:
|
||||
"@types/connect": "npm:*"
|
||||
"@types/node": "npm:*"
|
||||
checksum: bec2b8a97861a960ee415f7ab3c2aeb7f4d779fd364d27ddee46057897ea571735f1f854f5ee41682964315d4e3699f62427998b9c21851d773398ef535f0612
|
||||
checksum: aebeb200f25e8818d8cf39cd0209026750d77c9b85381cdd8deeb50913e4d18a1ebe4b74ca9b0b4d21952511eeaba5e9fbbf739b52731a2061e206ec60d568df
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/connect@npm:*":
|
||||
version: 3.4.37
|
||||
resolution: "@types/connect@npm:3.4.37"
|
||||
version: 3.4.38
|
||||
resolution: "@types/connect@npm:3.4.38"
|
||||
dependencies:
|
||||
"@types/node": "npm:*"
|
||||
checksum: 79fd5c32a8bb5c9548369e6da3221b6a820f3a8c5396d50f6f642712b9f4c1c881ef86bdf48994a4a279e81998563410b8843c5a10dde5521d5ef6a8ae944c3b
|
||||
checksum: 2e1cdba2c410f25649e77856505cd60223250fa12dff7a503e492208dbfdd25f62859918f28aba95315251fd1f5e1ffbfca1e25e73037189ab85dd3f8d0a148c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
@ -3074,14 +3141,14 @@ __metadata:
|
|||
linkType: hard
|
||||
|
||||
"@types/express-serve-static-core@npm:^4.17.33":
|
||||
version: 4.17.39
|
||||
resolution: "@types/express-serve-static-core@npm:4.17.39"
|
||||
version: 4.17.41
|
||||
resolution: "@types/express-serve-static-core@npm:4.17.41"
|
||||
dependencies:
|
||||
"@types/node": "npm:*"
|
||||
"@types/qs": "npm:*"
|
||||
"@types/range-parser": "npm:*"
|
||||
"@types/send": "npm:*"
|
||||
checksum: b23b005fddd2ba3f7142ec9713f06b5582c7712cdf99c3419d3972364903b348a103c3264d9a761d6497140e3b89bd416454684c4bdeff206b4c59b86e96428a
|
||||
checksum: dc166cbf4475c00a81fbcab120bf7477c527184be11ae149df7f26d9c1082114c68f8d387a2926fe80291b06477c8bbd9231ff4f5775de328e887695aefce269
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
@ -3134,9 +3201,9 @@ __metadata:
|
|||
linkType: hard
|
||||
|
||||
"@types/http-errors@npm:*":
|
||||
version: 2.0.3
|
||||
resolution: "@types/http-errors@npm:2.0.3"
|
||||
checksum: 717ce3e8f49a1facb7130fed934108fa8a51ab02089a1049c782e353e0e08e79bdfaac054c2a94db14ea400302e523276387363aa820eaf0031af8ba5d2941dc
|
||||
version: 2.0.4
|
||||
resolution: "@types/http-errors@npm:2.0.4"
|
||||
checksum: 494670a57ad4062fee6c575047ad5782506dd35a6b9ed3894cea65830a94367bd84ba302eb3dde331871f6d70ca287bfedb1b2cf658e6132cd2cbd427ab56836
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
@ -3238,16 +3305,16 @@ __metadata:
|
|||
linkType: hard
|
||||
|
||||
"@types/mime@npm:*":
|
||||
version: 3.0.3
|
||||
resolution: "@types/mime@npm:3.0.3"
|
||||
checksum: cef99f8cdc42af9de698027c2a20ba5df12bc9a89dcf5513e70103ebb55e00c5f5c585d02411f4b42fde0e78488342f1b1d3e3546a59a3da42e95fdc616e01eb
|
||||
version: 3.0.4
|
||||
resolution: "@types/mime@npm:3.0.4"
|
||||
checksum: db478bc0f99e40f7b3e01d356a9bdf7817060808a294978111340317bcd80ca35382855578c5b60fbc84ae449674bd9bb38427b18417e1f8f19e4f72f8b242cd
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/mime@npm:^1":
|
||||
version: 1.3.4
|
||||
resolution: "@types/mime@npm:1.3.4"
|
||||
checksum: a0a16d26c0e70a1b133e26e7c46b70b3136b7e894396bdb7de1c642f4ac87fdbbba26bf56cf73f001312289d89de4f1c06ab745d9445850df45a5a802564c4d6
|
||||
version: 1.3.5
|
||||
resolution: "@types/mime@npm:1.3.5"
|
||||
checksum: c2ee31cd9b993804df33a694d5aa3fa536511a49f2e06eeab0b484fef59b4483777dbb9e42a4198a0809ffbf698081fdbca1e5c2218b82b91603dfab10a10fbc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
@ -3351,16 +3418,16 @@ __metadata:
|
|||
linkType: hard
|
||||
|
||||
"@types/qs@npm:*":
|
||||
version: 6.9.9
|
||||
resolution: "@types/qs@npm:6.9.9"
|
||||
checksum: aede2a4181a49ae8548a1354bac3f8235cb0c5aab066b10875a3e68e88a199e220f4284e7e2bb75a3c18e5d4ff6abe1a6ce0389ef31b63952cc45e0f4d885ba0
|
||||
version: 6.9.10
|
||||
resolution: "@types/qs@npm:6.9.10"
|
||||
checksum: 6be12e5f062d1b41eb037d59bf9cb65bc9410cedd5e6da832dfd7c8e2b3f4c91e81c9b90b51811140770e5052c6c4e8361181bd9437ddcd4515dc128b7c00353
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/range-parser@npm:*":
|
||||
version: 1.2.6
|
||||
resolution: "@types/range-parser@npm:1.2.6"
|
||||
checksum: 46e7fffc54cdacc8fb0cd576f8f9a6436453f0176205d6ec55434a460c7677e78e688673426d5db5e480501b2943ba08a16ececa3a354c222093551c7217fb8f
|
||||
version: 1.2.7
|
||||
resolution: "@types/range-parser@npm:1.2.7"
|
||||
checksum: 361bb3e964ec5133fa40644a0b942279ed5df1949f21321d77de79f48b728d39253e5ce0408c9c17e4e0fd95ca7899da36841686393b9f7a1e209916e9381a3c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
@ -3546,23 +3613,23 @@ __metadata:
|
|||
linkType: hard
|
||||
|
||||
"@types/send@npm:*":
|
||||
version: 0.17.3
|
||||
resolution: "@types/send@npm:0.17.3"
|
||||
version: 0.17.4
|
||||
resolution: "@types/send@npm:0.17.4"
|
||||
dependencies:
|
||||
"@types/mime": "npm:^1"
|
||||
"@types/node": "npm:*"
|
||||
checksum: 773a0cb55ea03eefbe9a0e6d42114e0f84968db30954a131aae9ba7e9ab984a4776915447ebdeab4412d7f11750126614b0b75e99413f75810045bdb3196554a
|
||||
checksum: 7f17fa696cb83be0a104b04b424fdedc7eaba1c9a34b06027239aba513b398a0e2b7279778af521f516a397ced417c96960e5f50fcfce40c4bc4509fb1a5883c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/serve-static@npm:*":
|
||||
version: 1.15.4
|
||||
resolution: "@types/serve-static@npm:1.15.4"
|
||||
version: 1.15.5
|
||||
resolution: "@types/serve-static@npm:1.15.5"
|
||||
dependencies:
|
||||
"@types/http-errors": "npm:*"
|
||||
"@types/mime": "npm:*"
|
||||
"@types/node": "npm:*"
|
||||
checksum: 061b38993bf8f2b5033f57147c8ec90e1d1a0d6f734958ceb531ba7cc31192fd272c999cdbc57ede8672787e3aa171ec142dc65a467c04078e43823e7476eb49
|
||||
checksum: 811d1a2f7e74a872195e7a013bcd87a2fb1edf07eaedcb9dcfd20c1eb4bc56ad4ea0d52141c13192c91ccda7c8aeb8a530d8a7e60b9c27f5990d7e62e0fecb03
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
@ -4694,21 +4761,21 @@ __metadata:
|
|||
linkType: hard
|
||||
|
||||
"babel-plugin-formatjs@npm:^10.5.1":
|
||||
version: 10.5.9
|
||||
resolution: "babel-plugin-formatjs@npm:10.5.9"
|
||||
version: 10.5.10
|
||||
resolution: "babel-plugin-formatjs@npm:10.5.10"
|
||||
dependencies:
|
||||
"@babel/core": "npm:^7.10.4"
|
||||
"@babel/helper-plugin-utils": "npm:^7.10.4"
|
||||
"@babel/plugin-syntax-jsx": "npm:7"
|
||||
"@babel/traverse": "npm:7"
|
||||
"@babel/types": "npm:^7.12.11"
|
||||
"@formatjs/icu-messageformat-parser": "npm:2.7.2"
|
||||
"@formatjs/ts-transformer": "npm:3.13.8"
|
||||
"@formatjs/icu-messageformat-parser": "npm:2.7.3"
|
||||
"@formatjs/ts-transformer": "npm:3.13.9"
|
||||
"@types/babel__core": "npm:^7.1.7"
|
||||
"@types/babel__helper-plugin-utils": "npm:^7.10.0"
|
||||
"@types/babel__traverse": "npm:^7.1.7"
|
||||
tslib: "npm:^2.4.0"
|
||||
checksum: 5e4127cf7b4b9b3306a9d0ab5b029831712d22db5e2117225ce706b55d222d09a7eba1f3720fdad7a99f61843b5cba107296fc11ae00a6f0941217d9322aa02e
|
||||
checksum: bff65cd2a88a0ae00eabab1d022ffc44c4385b7e529cac42375bb1828c678c7a71a78f644512e5d1dd8cd532d418c16acdbabcef2bf6670e24404f4f164a74ce
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
@ -6398,6 +6465,13 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"debounce@npm:^1.2.1":
|
||||
version: 1.2.1
|
||||
resolution: "debounce@npm:1.2.1"
|
||||
checksum: 6c9320aa0973fc42050814621a7a8a78146c1975799b5b3cc1becf1f77ba9a5aa583987884230da0842a03f385def452fad5d60db97c3d1c8b824e38a8edf500
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"debug@npm:2.6.9, debug@npm:^2.2.0, debug@npm:^2.3.3":
|
||||
version: 2.6.9
|
||||
resolution: "debug@npm:2.6.9"
|
||||
|
@ -8871,7 +8945,7 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"html-escaper@npm:^2.0.0":
|
||||
"html-escaper@npm:^2.0.0, html-escaper@npm:^2.0.2":
|
||||
version: 2.0.2
|
||||
resolution: "html-escaper@npm:2.0.2"
|
||||
checksum: 208e8a12de1a6569edbb14544f4567e6ce8ecc30b9394fcaa4e7bb1e60c12a7c9a1ed27e31290817157e8626f3a4f29e76c8747030822eb84a6abb15c255f0a0
|
||||
|
@ -9271,15 +9345,15 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"intl-messageformat@npm:10.5.7, intl-messageformat@npm:^10.3.5":
|
||||
version: 10.5.7
|
||||
resolution: "intl-messageformat@npm:10.5.7"
|
||||
"intl-messageformat@npm:10.5.8, intl-messageformat@npm:^10.3.5":
|
||||
version: 10.5.8
|
||||
resolution: "intl-messageformat@npm:10.5.8"
|
||||
dependencies:
|
||||
"@formatjs/ecma402-abstract": "npm:1.17.4"
|
||||
"@formatjs/ecma402-abstract": "npm:1.18.0"
|
||||
"@formatjs/fast-memoize": "npm:2.2.0"
|
||||
"@formatjs/icu-messageformat-parser": "npm:2.7.2"
|
||||
"@formatjs/icu-messageformat-parser": "npm:2.7.3"
|
||||
tslib: "npm:^2.4.0"
|
||||
checksum: 7f341b3eb5b3d402167c99ca7fb98720c7ad553bed8a490b2210bd90ea9009a09f9030939307fecb111fce1454f31b4298b4f0a346999af627c86f8164a5c547
|
||||
checksum: 1d2854aae8471ec48165ca265760d6c5b1814eca831c88db698eb29b5ed20bee21ca8533090c9d28d9c6f1d844dda210b0bc58a2e036446158fae0845e5eed4f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
@ -11000,20 +11074,6 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lodash.escape@npm:^4.0.1":
|
||||
version: 4.0.1
|
||||
resolution: "lodash.escape@npm:4.0.1"
|
||||
checksum: 90ade409cec05b6869090476952fdfb84d4d87b1ff4a0e03ebd590f980d9a1248d93ba14579f10d80c6429e4d6af13ba137c28db64cae6dadb71442e54a3ad2b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lodash.flatten@npm:^4.4.0":
|
||||
version: 4.4.0
|
||||
resolution: "lodash.flatten@npm:4.4.0"
|
||||
checksum: 97e8f0d6b61fe4723c02ad0c6e67e51784c4a2c48f56ef283483e556ad01594cf9cec9c773e177bbbdbdb5d19e99b09d2487cb6b6e5dc405c2693e93b125bd3a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lodash.get@npm:^4.0":
|
||||
version: 4.4.2
|
||||
resolution: "lodash.get@npm:4.4.2"
|
||||
|
@ -11028,13 +11088,6 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lodash.invokemap@npm:^4.6.0":
|
||||
version: 4.6.0
|
||||
resolution: "lodash.invokemap@npm:4.6.0"
|
||||
checksum: 2bcc5f4b8782a316d55ff139215eb797f576f0f6d3db2755ebba7b35fd6061f8cbe81702a72a30bc6d70073a5dcc461f7570eaddcc9184c2e42ec3023645c6a1
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lodash.isarguments@npm:^3.1.0":
|
||||
version: 3.1.0
|
||||
resolution: "lodash.isarguments@npm:3.1.0"
|
||||
|
@ -11077,13 +11130,6 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lodash.pullall@npm:^4.2.0":
|
||||
version: 4.2.0
|
||||
resolution: "lodash.pullall@npm:4.2.0"
|
||||
checksum: b129e8d879258c7db04a7dc1c23dd9e37c52f63a04e105faa8d2ab55e97b5a170d5e15cffbb732a36e7f48c4345c07b6fbddfe50e1f5ec301492b6f64a92040c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lodash.sortby@npm:^4.7.0":
|
||||
version: 4.7.0
|
||||
resolution: "lodash.sortby@npm:4.7.0"
|
||||
|
@ -11105,13 +11151,6 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lodash.uniqby@npm:^4.7.0":
|
||||
version: 4.7.0
|
||||
resolution: "lodash.uniqby@npm:4.7.0"
|
||||
checksum: c505c0de20ca759599a2ba38710e8fb95ff2d2028e24d86c901ef2c74be8056518571b9b754bfb75053b2818d30dd02243e4a4621a6940c206bbb3f7626db656
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lodash@npm:^4.17.10, lodash@npm:^4.17.11, lodash@npm:^4.17.14, lodash@npm:^4.17.15, lodash@npm:^4.17.20, lodash@npm:^4.17.21":
|
||||
version: 4.17.21
|
||||
resolution: "lodash@npm:4.17.21"
|
||||
|
@ -13678,18 +13717,18 @@ __metadata:
|
|||
linkType: hard
|
||||
|
||||
"react-intl@npm:^6.4.2":
|
||||
version: 6.5.4
|
||||
resolution: "react-intl@npm:6.5.4"
|
||||
version: 6.5.5
|
||||
resolution: "react-intl@npm:6.5.5"
|
||||
dependencies:
|
||||
"@formatjs/ecma402-abstract": "npm:1.17.4"
|
||||
"@formatjs/icu-messageformat-parser": "npm:2.7.2"
|
||||
"@formatjs/intl": "npm:2.9.8"
|
||||
"@formatjs/intl-displaynames": "npm:6.6.3"
|
||||
"@formatjs/intl-listformat": "npm:7.5.2"
|
||||
"@formatjs/ecma402-abstract": "npm:1.18.0"
|
||||
"@formatjs/icu-messageformat-parser": "npm:2.7.3"
|
||||
"@formatjs/intl": "npm:2.9.9"
|
||||
"@formatjs/intl-displaynames": "npm:6.6.4"
|
||||
"@formatjs/intl-listformat": "npm:7.5.3"
|
||||
"@types/hoist-non-react-statics": "npm:^3.3.1"
|
||||
"@types/react": "npm:16 || 17 || 18"
|
||||
hoist-non-react-statics: "npm:^3.3.2"
|
||||
intl-messageformat: "npm:10.5.7"
|
||||
intl-messageformat: "npm:10.5.8"
|
||||
tslib: "npm:^2.4.0"
|
||||
peerDependencies:
|
||||
react: ^16.6.0 || 17 || 18
|
||||
|
@ -13697,7 +13736,7 @@ __metadata:
|
|||
peerDependenciesMeta:
|
||||
typescript:
|
||||
optional: true
|
||||
checksum: 1117a7f866b103abf88a4087f5fe8b854d9c069c69444c592f8431e7d28c9b90423f7b50e550be0f2f173b7563e943bcc9238e80f6747181f81861275f6e2ce7
|
||||
checksum: 9ff6200f195557804b735d618ee593aed7848e84213ac4eb9c57708f55c0d93232e0dd338c990348ba3b1d73dca071502a2051d4a2790838d962c3ccde87fa6c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
@ -17019,29 +17058,25 @@ __metadata:
|
|||
linkType: hard
|
||||
|
||||
"webpack-bundle-analyzer@npm:^4.8.0":
|
||||
version: 4.9.1
|
||||
resolution: "webpack-bundle-analyzer@npm:4.9.1"
|
||||
version: 4.10.0
|
||||
resolution: "webpack-bundle-analyzer@npm:4.10.0"
|
||||
dependencies:
|
||||
"@discoveryjs/json-ext": "npm:0.5.7"
|
||||
acorn: "npm:^8.0.4"
|
||||
acorn-walk: "npm:^8.0.0"
|
||||
commander: "npm:^7.2.0"
|
||||
debounce: "npm:^1.2.1"
|
||||
escape-string-regexp: "npm:^4.0.0"
|
||||
gzip-size: "npm:^6.0.0"
|
||||
html-escaper: "npm:^2.0.2"
|
||||
is-plain-object: "npm:^5.0.0"
|
||||
lodash.debounce: "npm:^4.0.8"
|
||||
lodash.escape: "npm:^4.0.1"
|
||||
lodash.flatten: "npm:^4.4.0"
|
||||
lodash.invokemap: "npm:^4.6.0"
|
||||
lodash.pullall: "npm:^4.2.0"
|
||||
lodash.uniqby: "npm:^4.7.0"
|
||||
opener: "npm:^1.5.2"
|
||||
picocolors: "npm:^1.0.0"
|
||||
sirv: "npm:^2.0.3"
|
||||
ws: "npm:^7.3.1"
|
||||
bin:
|
||||
webpack-bundle-analyzer: lib/bin/analyzer.js
|
||||
checksum: dd047c306471e6c389d6d4156ff22402e587140310a065a6191ee380f8251063f73a8ec6ac6d977c1cd634dbb717e2522b5d0b6cc9b0e847d4f15737fd9c65c9
|
||||
checksum: f812a8d3c0198ce518baf742bff656526f3eae69fb7a64c7f0c9cff202f6fb3380cabf3baaae965b8d6ffbbb6fb802eacb373fca03a596a38b01b84cfb2e8329
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue