fix!: remove esm package, use native Node ES modules (#2064)

BREAKING CHANGE: Node v12.20+, v14.14+, or v16.0+ is required

* fix!: remove esm package, use native Node ES modules

* fix: fix some CJS imports
This commit is contained in:
Nolan Lawson 2021-07-04 20:19:04 -07:00 committed by GitHub
parent c5de673990
commit 16e66346d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
451 changed files with 5664 additions and 1415 deletions

View File

@ -1,5 +1,7 @@
version: 2.1
orbs:
browser-tools: circleci/browser-tools@1.1.3
workflows:
version: 2
build_and_test:
@ -15,13 +17,11 @@ executors:
node:
working_directory: ~/pinafore
docker:
# we want Node v12, not v14
# see https://discuss.circleci.com/t/build-failed-the-engine-node-is-incompatible-with-this-module-expected-version-12-x-got-14-15-0/37921/7
- image: circleci/ruby@sha256:b018ec2a8f0bbf06880735d2801402bad316c465edb60663be83ac8f1086b805
- image: cimg/ruby:2.7.2-browsers
node_and_ruby:
working_directory: ~/pinafore
docker:
- image: circleci/ruby@sha256:b018ec2a8f0bbf06880735d2801402bad316c465edb60663be83ac8f1086b805
- image: cimg/ruby:2.7.2-browsers
- image: circleci/postgres:12.2
environment:
POSTGRES_USER: pinafore
@ -30,6 +30,45 @@ executors:
BROWSER: chrome:headless
- image: circleci/redis:5-alpine
commands:
install_mastodon_system_dependencies:
description: Install system dependencies that Mastodon requires
steps:
- run:
name: Install system dependencies
command: |
sudo apt-get update
sudo apt-get install -y \
ffmpeg \
fonts-noto-color-emoji \
imagemagick \
libicu-dev \
libidn11-dev \
libprotobuf-dev \
postgresql-contrib \
protobuf-compiler
install_browsers:
description: Install browsers and tools
steps:
- browser-tools/install-chrome:
chrome-version: 91.0.4472.114
- browser-tools/install-chromedriver
- run:
name: "Check browser version"
command: |
google-chrome --version
install_node:
description: Install Node.js
steps:
- run:
name: "Install Node.js"
# via https://circleci.com/docs/2.0/circleci-images/#notes-on-pinning-images
command: |
curl -sSL "https://nodejs.org/dist/v12.22.2/node-v12.22.2-linux-x64.tar.xz" \
| sudo tar --strip-components=2 -xJ -C /usr/local/bin/ node-v12.22.2-linux-x64/bin/node
- run:
name: Check current version of node
command: node -v
save_workspace:
description: Persist workspace
steps:
@ -47,13 +86,13 @@ commands:
steps:
- restore_cache:
name: Restore yarn cache
key: yarn-v3-{{ checksum "yarn.lock" }}
key: yarn-v4-{{ checksum "yarn.lock" }}
save_yarn_cache:
description: Save yarn cache
steps:
- save_cache:
name: Save yarn cache
key: yarn-v3-{{ checksum "yarn.lock" }}
key: yarn-v4-{{ checksum "yarn.lock" }}
paths:
- ~/.cache/yarn
restore_yarn_cache_mastodon:
@ -61,13 +100,13 @@ commands:
steps:
- restore_cache:
name: Restore yarn cache for Mastodon
key: yarn-v3-{{ checksum "mastodon/yarn.lock" }}
key: yarn-v4-{{ checksum "mastodon/yarn.lock" }}
save_yarn_cache_mastodon:
description: Save yarn cache for Mastodon
steps:
- save_cache:
name: Save yarn cache for Mastodon
key: yarn-v3-{{ checksum "mastodon/yarn.lock" }}
key: yarn-v4-{{ checksum "mastodon/yarn.lock" }}
paths:
- ~/.cache/yarn
restore_bundler_cache:
@ -75,23 +114,18 @@ commands:
steps:
- restore_cache:
name: Restore bundler cache
key: bundler-v2-{{ checksum "mastodon/Gemfile.lock" }}
key: bundler-v4-{{ checksum "mastodon/Gemfile.lock" }}
save_bundler_cache:
description: Save bundler cache
steps:
- save_cache:
name: Save bundler cache
key: bundler-v2-{{ checksum "mastodon/Gemfile.lock" }}
key: bundler-v4-{{ checksum "mastodon/Gemfile.lock" }}
paths:
- mastodon/vendor/bundle
install_mastodon:
description: Install Mastodon and set up Postgres/Redis
steps:
- run:
name: Install system dependencies
command: |
sudo apt-get update
sudo apt-get install -y ffmpeg fonts-noto-color-emoji libicu-dev libidn11-dev libprotobuf-dev postgresql-contrib protobuf-compiler
- run:
name: Clone mastodon
command: yarn clone-mastodon
@ -127,6 +161,7 @@ jobs:
executor: node
steps:
- checkout
- install_node
- restore_yarn_cache
- run:
name: Yarn install
@ -156,6 +191,9 @@ jobs:
integration_test_readonly:
executor: node_and_ruby
steps:
- install_mastodon_system_dependencies
- install_browsers
- install_node
- load_workspace
- install_mastodon
- run:
@ -164,6 +202,9 @@ jobs:
integration_test_readwrite:
executor: node_and_ruby
steps:
- install_mastodon_system_dependencies
- install_browsers
- install_node
- load_workspace
- install_mastodon
- run:

1
.gitignore vendored
View File

@ -14,3 +14,4 @@ yarn-error.log
.now
.vercel
/webpack/*.cjs

View File

@ -1,9 +1,10 @@
import path from 'path'
import fs from 'fs'
import { promisify } from 'util'
import { LOCALE } from '../src/routes/_static/intl'
import { getIntl, trimWhitespace } from './getIntl'
import { LOCALE } from '../src/routes/_static/intl.js'
import { getIntl, trimWhitespace } from './getIntl.js'
const __dirname = path.dirname(new URL(import.meta.url).pathname)
const readFile = promisify(fs.readFile)
const writeFile = promisify(fs.writeFile)

View File

@ -5,13 +5,12 @@ import path from 'path'
import { rollup } from 'rollup'
import { terser } from 'rollup-plugin-terser'
import replace from '@rollup/plugin-replace'
import fromPairs from 'lodash-es/fromPairs'
import { themes } from '../src/routes/_static/themes'
import terserOptions from './terserOptions'
import { themes } from '../src/routes/_static/themes.js'
import terserOptions from './terserOptions.js'
const __dirname = path.dirname(new URL(import.meta.url).pathname)
const writeFile = promisify(fs.writeFile)
const themeColors = fromPairs(themes.map(_ => ([_.name, _.color])))
const themeColors = Object.fromEntries(themes.map(_ => ([_.name, _.color])))
export async function buildInlineScript () {
const inlineScriptPath = path.join(__dirname, '../src/inline-script/inline-script.js')
@ -42,7 +41,7 @@ export async function buildInlineScript () {
const checksum = crypto.createHash('sha256').update(fullCode, 'utf8').digest('base64')
await writeFile(path.resolve(__dirname, '../src/inline-script/checksum.js'),
`module.exports = ${JSON.stringify(checksum)}`, 'utf8')
`export default ${JSON.stringify(checksum)}`, 'utf8')
await writeFile(path.resolve(__dirname, '../static/inline-script.js.map'),
map.toString(), 'utf8')

View File

@ -3,10 +3,12 @@ import path from 'path'
import fs from 'fs'
import { promisify } from 'util'
import cssDedoupe from 'css-dedoupe'
import { TextDecoder } from 'text-encoding'
import textEncodingPackage from 'text-encoding'
const { TextDecoder } = textEncodingPackage
const writeFile = promisify(fs.writeFile)
const readdir = promisify(fs.readdir)
const __dirname = path.dirname(new URL(import.meta.url).pathname)
const globalScss = path.join(__dirname, '../src/scss/global.scss')
const defaultThemeScss = path.join(__dirname, '../src/scss/themes/_default.scss')

View File

@ -1,10 +1,13 @@
import svgs from './svgs'
import svgs from './svgs.js'
import path from 'path'
import fs from 'fs'
import { promisify } from 'util'
import { optimize } from 'svgo'
import $ from 'cheerio'
import cheerioPackage from 'cheerio'
const { default: $ } = cheerioPackage
const __dirname = path.dirname(new URL(import.meta.url).pathname)
const readFile = promisify(fs.readFile)
const writeFile = promisify(fs.writeFile)

View File

@ -2,15 +2,18 @@ import chokidar from 'chokidar'
import fs from 'fs'
import path from 'path'
import { promisify } from 'util'
import { buildSass } from './build-sass'
import { buildInlineScript } from './build-inline-script'
import { buildSvg } from './build-svg'
import { buildSass } from './build-sass.js'
import { buildInlineScript } from './build-inline-script.js'
import { buildSvg } from './build-svg.js'
import { performance } from 'perf_hooks'
import debounce from 'lodash-es/debounce'
import applyIntl from '../webpack/svelte-intl-loader'
import { LOCALE } from '../src/routes/_static/intl'
import { getLangDir } from 'rtl-detect'
import { debounce } from '../src/routes/_thirdparty/lodash/timers.js'
import applyIntl from '../webpack/svelte-intl-loader.js'
import { LOCALE } from '../src/routes/_static/intl.js'
import rtlDetectPackage from 'rtl-detect'
const { getLangDir } = rtlDetectPackage
const __dirname = path.dirname(new URL(import.meta.url).pathname)
const writeFile = promisify(fs.writeFile)
const LOCALE_DIRECTION = getLangDir(LOCALE)
const DEBOUNCE = 500

View File

@ -5,11 +5,12 @@
import path from 'path'
import fs from 'fs'
import { promisify } from 'util'
import { routes } from '../__sapper__/service-worker'
import cloneDeep from 'lodash-es/cloneDeep'
import inlineScriptChecksum from '../src/inline-script/checksum'
import { sapperInlineScriptChecksums } from '../src/server/sapperInlineScriptChecksums'
import { routes } from '../__sapper__/service-worker.js'
import { cloneDeep } from '../src/routes/_utils/lodash-lite.js'
import inlineScriptChecksum from '../src/inline-script/checksum.js'
import { sapperInlineScriptChecksums } from '../src/server/sapperInlineScriptChecksums.js'
const __dirname = path.dirname(new URL(import.meta.url).pathname)
const writeFile = promisify(fs.writeFile)
const JSON_TEMPLATE = {

View File

@ -2,11 +2,13 @@ import { promisify } from 'util'
import childProcessPromise from 'child-process-promise'
import path from 'path'
import fs from 'fs'
import { envFile, RUBY_VERSION } from './mastodon-config'
import { envFile, RUBY_VERSION } from './mastodon-config.js'
import esMain from 'es-main'
const exec = childProcessPromise.exec
const stat = promisify(fs.stat)
const writeFile = promisify(fs.writeFile)
const __dirname = path.dirname(new URL(import.meta.url).pathname)
const dir = __dirname
const GIT_URL = 'https://github.com/tootsuite/mastodon.git'
@ -25,7 +27,7 @@ export default async function cloneMastodon () {
}
}
if (require.main === module) {
if (esMain(import.meta)) {
cloneMastodon().catch(err => {
console.error(err)
process.exit(1)

View File

@ -1,9 +1,19 @@
import { get } from 'lodash-es'
import { DEFAULT_LOCALE, LOCALE } from '../src/routes/_static/intl'
import path from 'path'
import { get } from '../src/routes/_utils/lodash-lite.js'
import { DEFAULT_LOCALE, LOCALE } from '../src/routes/_static/intl.js'
const intl = require(path.join(__dirname, '../src/intl', LOCALE + '.js')).default
const defaultIntl = require(path.join(__dirname, '../src/intl', DEFAULT_LOCALE + '.js')).default
import enUS from '../src/intl/en-US.js'
import fr from '../src/intl/fr.js'
import de from '../src/intl/de.js'
// TODO: make it so we don't have to explicitly list these out
const locales = {
'en-US': enUS,
fr,
de
}
const intl = locales[LOCALE]
const defaultIntl = locales[DEFAULT_LOCALE]
export function warningOrError (message) { // avoid crashing the whole server on `yarn dev`
if (process.env.NODE_ENV === 'production') {
@ -14,6 +24,7 @@ export function warningOrError (message) { // avoid crashing the whole server on
}
export function getIntl (path) {
path = path.split('.')
const res = get(intl, path, get(defaultIntl, path))
if (typeof res !== 'string') {
return warningOrError('Unknown intl string: ' + JSON.stringify(path))

View File

@ -2,12 +2,14 @@ import { promisify } from 'util'
import childProcessPromise from 'child-process-promise'
import path from 'path'
import fs from 'fs'
import { DB_NAME, DB_PASS, DB_USER, mastodonDir, env } from './mastodon-config'
import { DB_NAME, DB_PASS, DB_USER, mastodonDir, env } from './mastodon-config.js'
import mkdirp from 'mkdirp'
import esMain from 'es-main'
const exec = childProcessPromise.exec
const stat = promisify(fs.stat)
const writeFile = promisify(fs.writeFile)
const __dirname = path.dirname(new URL(import.meta.url).pathname)
const dir = __dirname
async function setupMastodonDatabase () {
@ -69,7 +71,7 @@ export default async function installMastodon () {
await installMastodonDependencies()
}
if (require.main === module) {
if (esMain(import.meta)) {
installMastodon().catch(err => {
console.error(err)
process.exit(1)

View File

@ -17,10 +17,9 @@ DB_NAME=${DB_NAME}
DB_PASS=${DB_PASS}
`
// Need a Ruby version that CircleCI bundles with Node v12, not Node v14 which doesn't
// work for streaming
export const RUBY_VERSION = '2.6.6'
export const RUBY_VERSION = '2.7.2'
const __dirname = path.dirname(new URL(import.meta.url).pathname)
export const mastodonDir = path.join(__dirname, '../mastodon')
export const env = Object.assign({}, process.env, {

View File

@ -1,4 +1,4 @@
import times from 'lodash-es/times'
import { times } from '../src/routes/_utils/lodash-lite.js'
function unrollThread (user, prefix, privacy, thread) {
const res = []

View File

@ -1,13 +1,13 @@
import { actions } from './mastodon-data'
import { users } from '../tests/users'
import { postStatus } from '../src/routes/_api/statuses'
import { followAccount } from '../src/routes/_api/follow'
import { favoriteStatus } from '../src/routes/_api/favorite'
import { reblogStatus } from '../src/routes/_api/reblog'
import { actions } from './mastodon-data.js'
import { users } from '../tests/users.js'
import { postStatus } from '../src/routes/_api/statuses.js'
import { followAccount } from '../src/routes/_api/follow.js'
import { favoriteStatus } from '../src/routes/_api/favorite.js'
import { reblogStatus } from '../src/routes/_api/reblog.js'
import fetch from 'node-fetch'
import FileApi from 'file-api'
import { pinStatus } from '../src/routes/_api/pin'
import { submitMedia } from '../tests/submitMedia'
import { pinStatus } from '../src/routes/_api/pin.js'
import { submitMedia } from '../tests/submitMedia.js'
global.File = FileApi.File
global.FormData = FileApi.FormData

View File

@ -1,10 +1,10 @@
import { restoreMastodonData } from './restore-mastodon-data'
import { restoreMastodonData } from './restore-mastodon-data.js'
import childProcessPromise from 'child-process-promise'
import fs from 'fs'
import { waitForMastodonUiToStart, waitForMastodonApiToStart } from './wait-for-mastodon-to-start'
import cloneMastodon from './clone-mastodon'
import installMastodon from './install-mastodon'
import { mastodonDir, env } from './mastodon-config'
import { waitForMastodonUiToStart, waitForMastodonApiToStart } from './wait-for-mastodon-to-start.js'
import cloneMastodon from './clone-mastodon.js'
import installMastodon from './install-mastodon.js'
import { mastodonDir, env } from './mastodon-config.js'
const spawn = childProcessPromise.spawn

View File

@ -1,4 +1,4 @@
module.exports = [
export default [
{ id: 'pinafore-logo', src: 'src/static/sailboat.svg', inline: true },
{ id: 'fa-bell', src: 'src/thirdparty/font-awesome-svg-png/white/svg/bell.svg', inline: true },
{ id: 'fa-users', src: 'src/thirdparty/font-awesome-svg-png/white/svg/users.svg', inline: true },

View File

@ -1,4 +1,4 @@
module.exports = {
export default {
ecma: 8,
mangle: true,
compress: {

View File

@ -1,5 +1,6 @@
import fetch from 'node-fetch'
import { actions } from './mastodon-data'
import { actions } from './mastodon-data.js'
import esMain from 'es-main'
const numStatuses = actions
.map(_ => _.post || _.boost)
@ -26,7 +27,7 @@ async function waitForMastodonData () {
console.log('Mastodon data populated')
}
if (require.main === module) {
if (esMain(import.meta)) {
waitForMastodonData().catch(err => {
console.error(err)
process.exit(1)

View File

@ -1,4 +1,5 @@
import fetch from 'node-fetch'
import esMain from 'es-main'
export async function waitForMastodonUiToStart () {
while (true) {
@ -30,7 +31,7 @@ export async function waitForMastodonApiToStart () {
console.log('Mastodon API started up')
}
if (require.main === module) {
if (esMain(import.meta)) {
Promise.resolve()
.then(waitForMastodonApiToStart)
.then(waitForMastodonUiToStart).catch(err => {

View File

@ -2,24 +2,29 @@
"name": "pinafore",
"description": "Alternative web client for Mastodon",
"version": "1.24.5",
"type": "module",
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"scripts": {
"lint": "standard && standard --plugin html 'src/routes/**/*.html'",
"lint-fix": "standard --fix && standard --fix --plugin html 'src/routes/**/*.html'",
"dev": "run-s build-template-html build-assets serve-dev",
"dev": "run-s before-build serve-dev",
"serve-dev": "run-p --race build-template-html-watch sapper-dev",
"sapper-dev": "cross-env NODE_ENV=development PORT=4002 node -r esm ./node_modules/sapper/sapper dev",
"before-build": "run-s build-template-html build-assets",
"sapper-dev": "cross-env NODE_ENV=development PORT=4002 WEBPACK_CONFIG_FILE=webpack/webpack.config.cjs SERVER_FILE_EXT=cjs node ./node_modules/sapper/sapper dev",
"before-build": "run-p build-template-html build-assets build-webpack-config",
"build": "cross-env NODE_ENV=production run-s build-steps",
"build-steps": "run-s before-build sapper-export build-vercel-json",
"sapper-build": "node -r esm ./node_modules/sapper/sapper build",
"sapper-build": "cross-env WEBPACK_CONFIG_FILE=webpack/webpack.config.cjs SERVER_FILE_EXT=cjs node ./node_modules/sapper/sapper build",
"start": "node server.js",
"build-and-start": "run-s build start",
"build-template-html": "node -r esm ./bin/build-template-html.js",
"build-template-html-watch": "node -r esm ./bin/build-template-html.js --watch",
"build-assets": "node -r esm ./bin/build-assets.js",
"clone-mastodon": "node -r esm ./bin/clone-mastodon.js",
"install-mastodon": "node -r esm ./bin/install-mastodon.js",
"run-mastodon": "node -r esm ./bin/run-mastodon.js",
"build-template-html": "node ./bin/build-template-html.js",
"build-template-html-watch": "node ./bin/build-template-html.js --watch",
"build-assets": "node ./bin/build-assets.js",
"build-webpack-config": "rollup -c ./webpack/rollup.config.js",
"clone-mastodon": "node ./bin/clone-mastodon.js",
"install-mastodon": "node ./bin/install-mastodon.js",
"run-mastodon": "node ./bin/run-mastodon.js",
"test": "cross-env BROWSER=chrome:headless run-s test-browser",
"test-browser": "run-p --race run-mastodon build-and-start test-mastodon",
"test-mastodon": "run-s wait-for-mastodon-to-start wait-for-mastodon-data testcafe",
@ -28,25 +33,27 @@
"testcafe": "run-s testcafe-suite0 testcafe-suite1",
"testcafe-suite0": "cross-env-shell testcafe -c 2 $BROWSER tests/spec/0*",
"testcafe-suite1": "cross-env-shell testcafe $BROWSER tests/spec/1*",
"test-unit": "NODE_ENV=test mocha -r esm -r bin/browser-shim.js tests/unit/",
"test-unit": "NODE_ENV=test mocha -r bin/browser-shim.js tests/unit/",
"test-in-ci-suite0": "cross-env BROWSER=chrome:headless run-p --race run-mastodon start test-mastodon-suite0",
"test-in-ci-suite1": "cross-env BROWSER=chrome:headless run-p --race run-mastodon start test-mastodon-suite1",
"wait-for-mastodon-to-start": "node -r esm bin/wait-for-mastodon-to-start.js",
"wait-for-mastodon-data": "node -r esm bin/wait-for-mastodon-data.js",
"wait-for-mastodon-to-start": "node bin/wait-for-mastodon-to-start.js",
"wait-for-mastodon-data": "node bin/wait-for-mastodon-data.js",
"backup-mastodon-data": "./bin/backup-mastodon-data.sh",
"sapper-export": "cross-env PORT=22939 node -r esm ./node_modules/sapper/sapper export",
"sapper-export": "cross-env PORT=22939 WEBPACK_CONFIG_FILE=webpack/webpack.config.cjs SERVER_FILE_EXT=cjs node ./node_modules/sapper/sapper export",
"print-export-info": "node ./bin/print-export-info.js",
"export-steps": "run-s before-build sapper-export print-export-info",
"export": "cross-env NODE_ENV=production run-s export-steps",
"now-build": "run-s export",
"build-vercel-json": "node -r esm bin/build-vercel-json.js"
"build-vercel-json": "node bin/build-vercel-json.js"
},
"dependencies": {
"@formatjs/intl-listformat": "^6.2.6",
"@formatjs/intl-locale": "^2.4.33",
"@formatjs/intl-pluralrules": "^4.0.28",
"@formatjs/intl-relativetimeformat": "^9.1.7",
"@rollup/plugin-json": "^4.1.0",
"@rollup/plugin-replace": "^2.4.2",
"@stdlib/utils-noop": "^0.0.6",
"arrow-key-navigation": "^1.2.0",
"blurhash": "^1.1.3",
"cheerio": "1.0.0-rc.10",
@ -60,6 +67,7 @@
"emoji-picker-element-data": "^1.2.0",
"emoji-regex": "^9.2.2",
"encoding": "^0.1.13",
"es-main": "^1.0.2",
"escape-html": "^1.0.3",
"esm": "^3.2.25",
"events-light": "^1.0.5",
@ -75,8 +83,6 @@
"is-emoji-supported": "^0.0.5",
"li": "^1.3.0",
"localstorage-memory": "^1.0.3",
"lodash-es": "4.17.15",
"lodash-webpack-plugin": "^0.11.6",
"mkdirp": "^1.0.4",
"node-fetch": "^2.6.1",
"npm-run-all": "^4.1.5",
@ -90,7 +96,7 @@
"rollup-plugin-terser": "^7.0.2",
"rtl-detect": "^1.0.3",
"safari-14-idb-fix": "^1.0.3",
"sapper": "nolanlawson/sapper#for-pinafore-25",
"sapper": "nolanlawson/sapper#for-pinafore-26",
"sass": "^1.35.1",
"stringz": "^2.1.0",
"svelte": "^2.16.1",
@ -118,10 +124,10 @@
"standard": "^16.0.3",
"testcafe": "^1.15.0-rc.3"
},
"engines": {
"node": ">= 8"
},
"standard": {
"ignore": [
"webpack/*.cjs"
],
"globals": [
"AbortController",
"Blob",

View File

@ -1,9 +1,16 @@
#!/usr/bin/env node
import fs from 'fs'
import path from 'path'
import express from 'express'
import compression from 'compression'
const path = require('path')
const express = require('express')
const compression = require('compression')
const { routes: rawRoutes } = require('./vercel.json')
const __dirname = path.dirname(new URL(import.meta.url).pathname)
// JSON files not supported in ESM yet
// https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c#how-can-i-import-json
const vercelJson = JSON.parse(fs.readFileSync(path.join(__dirname, 'vercel.json'), 'utf8'))
const { routes: rawRoutes } = vercelJson
const { PORT = 4002 } = process.env
const app = express()

View File

@ -1,12 +1,12 @@
import * as sapper from '../__sapper__/client.js'
import './routes/_utils/serviceWorkerClient'
import './routes/_utils/historyEvents'
import './routes/_utils/loadingMask'
import './routes/_utils/forceOnline'
import { mark, stop } from './routes/_utils/marks'
import { loadPolyfills } from './routes/_utils/polyfills/loadPolyfills'
import { loadNonCriticalPolyfills } from './routes/_utils/polyfills/loadNonCriticalPolyfills'
import { idbReady } from './routes/_utils/idbReady'
import './routes/_utils/serviceWorkerClient.js'
import './routes/_utils/historyEvents.js'
import './routes/_utils/loadingMask.js'
import './routes/_utils/forceOnline.js'
import { mark, stop } from './routes/_utils/marks.js'
import { loadPolyfills } from './routes/_utils/polyfills/loadPolyfills.js'
import { loadNonCriticalPolyfills } from './routes/_utils/polyfills/loadNonCriticalPolyfills.js'
import { idbReady } from './routes/_utils/idbReady.js'
Promise.all([idbReady(), loadPolyfills()]).then(() => {
mark('sapperStart')
@ -17,6 +17,6 @@ Promise.all([idbReady(), loadPolyfills()]).then(() => {
console.log('process.env.NODE_ENV', process.env.NODE_ENV)
if (module.hot) {
module.hot.accept()
if (import.meta.webpackHot) {
import.meta.webpackHot.accept()
}

View File

@ -3,12 +3,12 @@
// To allow CSP to work correctly, we also calculate a sha256 hash during
// the build process and write it to checksum.js.
import { INLINE_THEME, DEFAULT_THEME, switchToTheme } from '../routes/_utils/themeEngine'
import { basename } from '../routes/_api/utils'
import { onUserIsLoggedOut } from '../routes/_actions/onUserIsLoggedOut'
import { storeLite } from '../routes/_store/storeLite'
import { isIOSPre12Point2 } from '../routes/_utils/userAgent/isIOSPre12Point2'
import { isMac } from '../routes/_utils/userAgent/isMac'
import { INLINE_THEME, DEFAULT_THEME, switchToTheme } from '../routes/_utils/themeEngine.js'
import { basename } from '../routes/_api/utils.js'
import { onUserIsLoggedOut } from '../routes/_actions/onUserIsLoggedOut.js'
import { storeLite } from '../routes/_store/storeLite.js'
import { isIOSPre12Point2 } from '../routes/_utils/userAgent/isIOSPre12Point2.js'
import { isMac } from '../routes/_utils/userAgent/isMac.js'
window.__themeColors = process.env.THEME_COLORS

View File

@ -1,6 +1,6 @@
import { getAccountAccessibleName } from './getAccountAccessibleName'
import { POST_PRIVACY_OPTIONS } from '../_static/statuses'
import { formatIntl } from '../_utils/formatIntl'
import { getAccountAccessibleName } from './getAccountAccessibleName.js'
import { POST_PRIVACY_OPTIONS } from '../_static/statuses.js'
import { formatIntl } from '../_utils/formatIntl.js'
function getNotificationText (notification, omitEmojiInDisplayNames) {
if (!notification) {

View File

@ -1,4 +1,4 @@
import { removeEmoji } from '../_utils/removeEmoji'
import { removeEmoji } from '../_utils/removeEmoji.js'
export function getAccountAccessibleName (account, omitEmojiInDisplayNames) {
const emojis = account.emojis

View File

@ -1,7 +1,7 @@
import { getAccount } from '../_api/user'
import { getRelationship } from '../_api/relationships'
import { database } from '../_database/database'
import { store } from '../_store/store'
import { getAccount } from '../_api/user.js'
import { getRelationship } from '../_api/relationships.js'
import { database } from '../_database/database.js'
import { store } from '../_store/store.js'
async function _updateAccount (accountId, instanceName, accessToken) {
const localPromise = database.getAccount(instanceName, accountId)

View File

@ -1,12 +1,12 @@
import { getAccessTokenFromAuthCode, registerApplication, generateAuthLink } from '../_api/oauth'
import { getInstanceInfo } from '../_api/instance'
import { goto } from '../../../__sapper__/client'
import { DEFAULT_THEME, switchToTheme } from '../_utils/themeEngine'
import { store } from '../_store/store'
import { updateVerifyCredentialsForInstance } from './instances'
import { updateCustomEmojiForInstance } from './emoji'
import { database } from '../_database/database'
import { DOMAIN_BLOCKS } from '../_static/blocks'
import { getAccessTokenFromAuthCode, registerApplication, generateAuthLink } from '../_api/oauth.js'
import { getInstanceInfo } from '../_api/instance.js'
import { goto } from '../../../__sapper__/client.js'
import { DEFAULT_THEME, switchToTheme } from '../_utils/themeEngine.js'
import { store } from '../_store/store.js'
import { updateVerifyCredentialsForInstance } from './instances.js'
import { updateCustomEmojiForInstance } from './emoji.js'
import { database } from '../_database/database.js'
import { DOMAIN_BLOCKS } from '../_static/blocks.js'
const GENERIC_ERROR = `
Is this a valid Mastodon instance? Is a browser extension

View File

@ -1,11 +1,10 @@
import { mark, stop } from '../_utils/marks'
import { store } from '../_store/store'
import uniqBy from 'lodash-es/uniqBy'
import isEqual from 'lodash-es/isEqual'
import { database } from '../_database/database'
import { concat } from '../_utils/arrays'
import { scheduleIdleTask } from '../_utils/scheduleIdleTask'
import { timelineItemToSummary } from '../_utils/timelineItemToSummary'
import { mark, stop } from '../_utils/marks.js'
import { store } from '../_store/store.js'
import { uniqBy, isEqual } from '../_thirdparty/lodash/objects.js'
import { database } from '../_database/database.js'
import { concat } from '../_utils/arrays.js'
import { scheduleIdleTask } from '../_utils/scheduleIdleTask.js'
import { timelineItemToSummary } from '../_utils/timelineItemToSummary.js'
function getExistingItemIdsSet (instanceName, timelineName) {
const timelineItemSummaries = store.getForTimeline(instanceName, timelineName, 'timelineItemSummaries') || []

View File

@ -1,4 +1,4 @@
import { store } from '../_store/store'
import { store } from '../_store/store.js'
const emojiMapper = emoji => emoji.unicode ? emoji.unicode : `:${emoji.shortcodes[0]}:`
const hashtagMapper = hashtag => `#${hashtag.name}`

View File

@ -1,11 +1,11 @@
import { database } from '../_database/database'
import { store } from '../_store/store'
import { search } from '../_api/search'
import { SEARCH_RESULTS_LIMIT } from '../_static/autosuggest'
import { concat } from '../_utils/arrays'
import uniqBy from 'lodash-es/uniqBy'
import { scheduleIdleTask } from '../_utils/scheduleIdleTask'
import { RequestThrottler } from '../_utils/RequestThrottler'
import { database } from '../_database/database.js'
import { store } from '../_store/store.js'
import { search } from '../_api/search.js'
import { SEARCH_RESULTS_LIMIT } from '../_static/autosuggest.js'
import { concat } from '../_utils/arrays.js'
import { uniqBy } from '../_thirdparty/lodash/objects.js'
import { scheduleIdleTask } from '../_utils/scheduleIdleTask.js'
import { RequestThrottler } from '../_utils/RequestThrottler.js'
const DATABASE_SEARCH_RESULTS_LIMIT = 30

View File

@ -1,9 +1,9 @@
import { store } from '../_store/store'
import { scheduleIdleTask } from '../_utils/scheduleIdleTask'
import * as emojiDatabase from '../_utils/emojiDatabase'
import { SEARCH_RESULTS_LIMIT } from '../_static/autosuggest'
import { testEmojiSupported } from '../_utils/testEmojiSupported'
import { mark, stop } from '../_utils/marks'
import { store } from '../_store/store.js'
import { scheduleIdleTask } from '../_utils/scheduleIdleTask.js'
import * as emojiDatabase from '../_utils/emojiDatabase.js'
import { SEARCH_RESULTS_LIMIT } from '../_static/autosuggest.js'
import { testEmojiSupported } from '../_utils/testEmojiSupported.js'
import { mark, stop } from '../_utils/marks.js'
async function searchEmoji (searchText) {
let emojis = await emojiDatabase.findBySearchQuery(searchText)

View File

@ -1,9 +1,9 @@
import { search } from '../_api/search'
import { store } from '../_store/store'
import { scheduleIdleTask } from '../_utils/scheduleIdleTask'
import { SEARCH_RESULTS_LIMIT } from '../_static/autosuggest'
import { RequestThrottler } from '../_utils/RequestThrottler'
import { sum } from '../_utils/lodash-lite'
import { search } from '../_api/search.js'
import { store } from '../_store/store.js'
import { scheduleIdleTask } from '../_utils/scheduleIdleTask.js'
import { SEARCH_RESULTS_LIMIT } from '../_static/autosuggest.js'
import { RequestThrottler } from '../_utils/RequestThrottler.js'
import { sum } from '../_utils/lodash-lite.js'
const HASHTAG_SEARCH_LIMIT = 10

View File

@ -1,9 +1,9 @@
import { store } from '../_store/store'
import { blockAccount, unblockAccount } from '../_api/block'
import { toast } from '../_components/toast/toast'
import { updateLocalRelationship } from './accounts'
import { emit } from '../_utils/eventBus'
import { formatIntl } from '../_utils/formatIntl'
import { store } from '../_store/store.js'
import { blockAccount, unblockAccount } from '../_api/block.js'
import { toast } from '../_components/toast/toast.js'
import { updateLocalRelationship } from './accounts.js'
import { emit } from '../_utils/eventBus.js'
import { formatIntl } from '../_utils/formatIntl.js'
export async function setAccountBlocked (accountId, block, toastOnSuccess) {
const { currentInstance, accessToken } = store.get()

View File

@ -1,8 +1,8 @@
import { store } from '../_store/store'
import { toast } from '../_components/toast/toast'
import { bookmarkStatus, unbookmarkStatus } from '../_api/bookmark'
import { database } from '../_database/database'
import { formatIntl } from '../_utils/formatIntl'
import { store } from '../_store/store.js'
import { toast } from '../_components/toast/toast.js'
import { bookmarkStatus, unbookmarkStatus } from '../_api/bookmark.js'
import { database } from '../_database/database.js'
import { formatIntl } from '../_utils/formatIntl.js'
export async function setStatusBookmarkedOrUnbookmarked (statusId, bookmarked) {
const { currentInstance, accessToken } = store.get()

View File

@ -1,13 +1,13 @@
import { store } from '../_store/store'
import { toast } from '../_components/toast/toast'
import { postStatus as postStatusToServer } from '../_api/statuses'
import { addStatusOrNotification } from './addStatusOrNotification'
import { database } from '../_database/database'
import { emit } from '../_utils/eventBus'
import { putMediaMetadata } from '../_api/media'
import uniqBy from 'lodash-es/uniqBy'
import { scheduleIdleTask } from '../_utils/scheduleIdleTask'
import { formatIntl } from '../_utils/formatIntl'
import { store } from '../_store/store.js'
import { toast } from '../_components/toast/toast.js'
import { postStatus as postStatusToServer } from '../_api/statuses.js'
import { addStatusOrNotification } from './addStatusOrNotification.js'
import { database } from '../_database/database.js'
import { emit } from '../_utils/eventBus.js'
import { putMediaMetadata } from '../_api/media.js'
import { uniqBy } from '../_thirdparty/lodash/objects.js'
import { scheduleIdleTask } from '../_utils/scheduleIdleTask.js'
import { formatIntl } from '../_utils/formatIntl.js'
export async function insertHandleForReply (statusId) {
const { currentInstance } = store.get()

View File

@ -1,4 +1,4 @@
import { store } from '../_store/store'
import { store } from '../_store/store.js'
export function enablePoll (realm) {
store.setComposeData(realm, {

View File

@ -1,4 +1,4 @@
import { store } from '../_store/store'
import { store } from '../_store/store.js'
export function toggleContentWarningShown (realm) {
const shown = store.getComposeData(realm, 'contentWarningShown')

View File

@ -1,5 +1,5 @@
import { importShowCopyDialog } from '../_components/dialog/asyncDialogs/importShowCopyDialog.js'
import { toast } from '../_components/toast/toast'
import { toast } from '../_components/toast/toast.js'
export async function copyText (text) {
if (navigator.clipboard) { // not supported in all browsers

View File

@ -1,9 +1,9 @@
import { database } from '../_database/database'
import { decode as decodeBlurhash, init as initBlurhash } from '../_utils/blurhash'
import { mark, stop } from '../_utils/marks'
import { get } from '../_utils/lodash-lite'
import { statusHtmlToPlainText } from '../_utils/statusHtmlToPlainText'
import { scheduleIdleTask } from '../_utils/scheduleIdleTask'
import { database } from '../_database/database.js'
import { decode as decodeBlurhash, init as initBlurhash } from '../_utils/blurhash.js'
import { mark, stop } from '../_utils/marks.js'
import { get } from '../_utils/lodash-lite.js'
import { statusHtmlToPlainText } from '../_utils/statusHtmlToPlainText.js'
import { scheduleIdleTask } from '../_utils/scheduleIdleTask.js'
async function getNotification (instanceName, timelineType, timelineValue, itemId) {
return {

View File

@ -1,8 +1,8 @@
import { store } from '../_store/store'
import { deleteStatus } from '../_api/delete'
import { toast } from '../_components/toast/toast'
import { deleteStatus as deleteStatusLocally } from './deleteStatuses'
import { formatIntl } from '../_utils/formatIntl'
import { store } from '../_store/store.js'
import { deleteStatus } from '../_api/delete.js'
import { toast } from '../_components/toast/toast.js'
import { deleteStatus as deleteStatusLocally } from './deleteStatuses.js'
import { formatIntl } from '../_utils/formatIntl.js'
export async function doDeleteStatus (statusId) {
const { currentInstance, accessToken } = store.get()

View File

@ -1,7 +1,7 @@
import { statusHtmlToPlainText } from '../_utils/statusHtmlToPlainText'
import { statusHtmlToPlainText } from '../_utils/statusHtmlToPlainText.js'
import { importShowComposeDialog } from '../_components/dialog/asyncDialogs/importShowComposeDialog.js'
import { doDeleteStatus } from './delete'
import { store } from '../_store/store'
import { doDeleteStatus } from './delete.js'
import { store } from '../_store/store.js'
export async function deleteAndRedraft (status) {
const deleteStatusPromise = doDeleteStatus(status.id)

View File

@ -1,8 +1,8 @@
import { getIdsThatRebloggedThisStatus, getNotificationIdsForStatuses } from './statuses'
import { store } from '../_store/store'
import isEqual from 'lodash-es/isEqual'
import { database } from '../_database/database'
import { scheduleIdleTask } from '../_utils/scheduleIdleTask'
import { getIdsThatRebloggedThisStatus, getNotificationIdsForStatuses } from './statuses.js'
import { store } from '../_store/store.js'
import { isEqual } from '../_thirdparty/lodash/objects.js'
import { database } from '../_database/database.js'
import { scheduleIdleTask } from '../_utils/scheduleIdleTask.js'
function filterItemIdsFromTimelines (instanceName, timelineFilter, idFilter) {
const keys = ['timelineItemSummaries', 'timelineItemSummariesToAdd']

View File

@ -2,8 +2,8 @@
// Used in the integration tests. Can't see a problem with exposing this publicly
// since you would have to know the access token anyway.
import { store } from '../_store/store'
import { goto } from '../../../__sapper__/client'
import { store } from '../_store/store.js'
import { goto } from '../../../__sapper__/client.js'
export function doQuickLoginIfNecessary () {
const params = new URLSearchParams(location.search)

View File

@ -1,11 +1,11 @@
import {
cacheFirstUpdateAfter,
cacheFirstUpdateOnlyIfNotInCache
} from '../_utils/sync'
import { database } from '../_database/database'
import { getCustomEmoji } from '../_api/emoji'
import { store } from '../_store/store'
import isEqual from 'lodash-es/isEqual'
} from '../_utils/sync.js'
import { database } from '../_database/database.js'
import { getCustomEmoji } from '../_api/emoji.js'
import { store } from '../_store/store.js'
import { isEqual } from '../_thirdparty/lodash/objects.js'
async function syncEmojiForInstance (instanceName, syncMethod) {
await syncMethod(

View File

@ -1,8 +1,8 @@
import { favoriteStatus, unfavoriteStatus } from '../_api/favorite'
import { store } from '../_store/store'
import { toast } from '../_components/toast/toast'
import { database } from '../_database/database'
import { formatIntl } from '../_utils/formatIntl'
import { favoriteStatus, unfavoriteStatus } from '../_api/favorite.js'
import { store } from '../_store/store.js'
import { toast } from '../_components/toast/toast.js'
import { database } from '../_database/database.js'
import { formatIntl } from '../_utils/formatIntl.js'
export async function setFavorited (statusId, favorited) {
const { online } = store.get()

View File

@ -1,11 +1,11 @@
import { store } from '../_store/store'
import { createFilter, getFilters, updateFilter, deleteFilter as doDeleteFilter } from '../_api/filters'
import { cacheFirstUpdateAfter, cacheFirstUpdateOnlyIfNotInCache } from '../_utils/sync'
import { database } from '../_database/database'
import { isEqual } from 'lodash-es'
import { toast } from '../_components/toast/toast'
import { formatIntl } from '../_utils/formatIntl'
import { emit } from '../_utils/eventBus'
import { store } from '../_store/store.js'
import { createFilter, getFilters, updateFilter, deleteFilter as doDeleteFilter } from '../_api/filters.js'
import { cacheFirstUpdateAfter, cacheFirstUpdateOnlyIfNotInCache } from '../_utils/sync.js'
import { database } from '../_database/database.js'
import { isEqual } from '../_thirdparty/lodash/objects.js'
import { toast } from '../_components/toast/toast.js'
import { formatIntl } from '../_utils/formatIntl.js'
import { emit } from '../_utils/eventBus.js'
async function syncFilters (instanceName, syncMethod) {
const { loggedInInstances } = store.get()

View File

@ -1,8 +1,8 @@
import { store } from '../_store/store'
import { followAccount, unfollowAccount } from '../_api/follow'
import { toast } from '../_components/toast/toast'
import { updateLocalRelationship } from './accounts'
import { formatIntl } from '../_utils/formatIntl'
import { store } from '../_store/store.js'
import { followAccount, unfollowAccount } from '../_api/follow.js'
import { toast } from '../_components/toast/toast.js'
import { updateLocalRelationship } from './accounts.js'
import { formatIntl } from '../_utils/formatIntl.js'
export async function setAccountFollowed (accountId, follow, toastOnSuccess) {
const { currentInstance, accessToken } = store.get()

View File

@ -1,8 +1,8 @@
import { store } from '../_store/store'
import { cacheFirstUpdateAfter } from '../_utils/sync'
import { database } from '../_database/database'
import { getFollowRequests } from '../_api/followRequests'
import { get } from '../_utils/lodash-lite'
import { store } from '../_store/store.js'
import { cacheFirstUpdateAfter } from '../_utils/sync.js'
import { database } from '../_database/database.js'
import { getFollowRequests } from '../_api/followRequests.js'
import { get } from '../_utils/lodash-lite.js'
export async function updateFollowRequestCountIfLockedAccount (instanceName) {
const { verifyCredentials, loggedInInstances } = store.get()

View File

@ -1,5 +1,5 @@
import { store } from '../_store/store'
import { getTimeline } from '../_api/timelines'
import { store } from '../_store/store.js'
import { getTimeline } from '../_api/timelines.js'
export async function getRecentStatusesForAccount (accountId) {
const { currentInstance, accessToken } = store.get()

View File

@ -1,6 +1,6 @@
import { store } from '../_store/store'
import { goto } from '../../../__sapper__/client'
import { emit } from '../_utils/eventBus'
import { store } from '../_store/store.js'
import { goto } from '../../../__sapper__/client.js'
import { emit } from '../_utils/eventBus.js'
// Go to the search page, and also focus the search input. For accessibility
// and usability reasons, this only happens on pressing these particular hotkeys.

View File

@ -1,13 +1,13 @@
import { getVerifyCredentials } from '../_api/user'
import { store } from '../_store/store'
import { switchToTheme } from '../_utils/themeEngine'
import { toast } from '../_components/toast/toast'
import { goto } from '../../../__sapper__/client'
import { cacheFirstUpdateAfter } from '../_utils/sync'
import { getInstanceInfo } from '../_api/instance'
import { database } from '../_database/database'
import { getVerifyCredentials } from '../_api/user.js'
import { store } from '../_store/store.js'
import { switchToTheme } from '../_utils/themeEngine.js'
import { toast } from '../_components/toast/toast.js'
import { goto } from '../../../__sapper__/client.js'
import { cacheFirstUpdateAfter } from '../_utils/sync.js'
import { getInstanceInfo } from '../_api/instance.js'
import { database } from '../_database/database.js'
import { importVirtualListStore } from '../_utils/asyncModules/importVirtualListStore.js'
import { formatIntl } from '../_utils/formatIntl'
import { formatIntl } from '../_utils/formatIntl.js'
export function changeTheme (instanceName, newTheme) {
const { instanceThemes } = store.get()

View File

@ -1,7 +1,7 @@
import { store } from '../_store/store'
import { getLists } from '../_api/lists'
import { cacheFirstUpdateAfter, cacheFirstUpdateOnlyIfNotInCache } from '../_utils/sync'
import { database } from '../_database/database'
import { store } from '../_store/store.js'
import { getLists } from '../_api/lists.js'
import { cacheFirstUpdateAfter, cacheFirstUpdateOnlyIfNotInCache } from '../_utils/sync.js'
import { database } from '../_database/database.js'
async function syncLists (instanceName, syncMethod) {
const { loggedInInstances } = store.get()

View File

@ -1,9 +1,9 @@
import { store } from '../_store/store'
import { uploadMedia } from '../_api/media'
import { toast } from '../_components/toast/toast'
import { scheduleIdleTask } from '../_utils/scheduleIdleTask'
import { formatIntl } from '../_utils/formatIntl'
import { database } from '../_database/database'
import { store } from '../_store/store.js'
import { uploadMedia } from '../_api/media.js'
import { toast } from '../_components/toast/toast.js'
import { scheduleIdleTask } from '../_utils/scheduleIdleTask.js'
import { formatIntl } from '../_utils/formatIntl.js'
import { database } from '../_database/database.js'
export async function doMediaUpload (realm, file) {
const { currentInstance, accessToken } = store.get()

View File

@ -1,5 +1,5 @@
import { importShowComposeDialog } from '../_components/dialog/asyncDialogs/importShowComposeDialog.js'