chore: initial commit
This commit is contained in:
commit
8d84ebe491
23 changed files with 1968 additions and 0 deletions
178
.gitignore
vendored
Normal file
178
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore
|
||||
|
||||
# Logs
|
||||
|
||||
logs
|
||||
_.log
|
||||
npm-debug.log_
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# Caches
|
||||
|
||||
.cache
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
|
||||
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
|
||||
|
||||
# Runtime data
|
||||
|
||||
pids
|
||||
_.pid
|
||||
_.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Snowpack dependency directory (https://snowpack.dev/)
|
||||
|
||||
web_modules/
|
||||
|
||||
# TypeScript cache
|
||||
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
|
||||
.eslintcache
|
||||
|
||||
# Optional stylelint cache
|
||||
|
||||
.stylelintcache
|
||||
|
||||
# Microbundle cache
|
||||
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variable files
|
||||
|
||||
.env
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
|
||||
.next
|
||||
out
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
|
||||
.vuepress/dist
|
||||
|
||||
# vuepress v2.x temp and cache directory
|
||||
|
||||
.temp
|
||||
|
||||
# Docusaurus cache and generated files
|
||||
|
||||
.docusaurus
|
||||
|
||||
# Serverless directories
|
||||
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
|
||||
.vscode-test
|
||||
|
||||
# yarn v2
|
||||
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
|
||||
# IntelliJ based IDEs
|
||||
.idea
|
||||
|
||||
# Finder (MacOS) folder config
|
||||
.DS_Store
|
||||
|
||||
# Private
|
||||
.private
|
||||
15
README.md
Normal file
15
README.md
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# @revenge-mod/revenge
|
||||
|
||||
To install dependencies:
|
||||
|
||||
```bash
|
||||
bun install
|
||||
```
|
||||
|
||||
To run:
|
||||
|
||||
```bash
|
||||
bun run src/index.ts
|
||||
```
|
||||
|
||||
This project was created using `bun init` in bun v1.2.2. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime.
|
||||
69
biome.json
Normal file
69
biome.json
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
{
|
||||
"$schema": "https://biomejs.dev/schemas/1.8.2/schema.json",
|
||||
"organizeImports": {
|
||||
"enabled": true
|
||||
},
|
||||
"linter": {
|
||||
"enabled": true,
|
||||
"rules": {
|
||||
"recommended": true,
|
||||
"a11y": {
|
||||
"useKeyWithClickEvents": {
|
||||
"level": "off"
|
||||
}
|
||||
},
|
||||
"style": {
|
||||
"noCommaOperator": {
|
||||
"level": "off"
|
||||
},
|
||||
"noNonNullAssertion": {
|
||||
"level": "off"
|
||||
},
|
||||
"useNodejsImportProtocol": {
|
||||
"level": "off"
|
||||
}
|
||||
},
|
||||
"suspicious": {
|
||||
"noAssignInExpressions": {
|
||||
"level": "off"
|
||||
},
|
||||
"noExplicitAny": {
|
||||
"level": "off"
|
||||
},
|
||||
"noConfusingVoidType": {
|
||||
"level": "off"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"json": {
|
||||
"formatter": {
|
||||
"enabled": true,
|
||||
"indentStyle": "space",
|
||||
"indentWidth": 2
|
||||
},
|
||||
"parser": {
|
||||
"allowComments": true,
|
||||
"allowTrailingCommas": true
|
||||
}
|
||||
},
|
||||
"javascript": {
|
||||
"formatter": {
|
||||
"enabled": true,
|
||||
"lineEnding": "crlf",
|
||||
"arrowParentheses": "asNeeded",
|
||||
"indentStyle": "space",
|
||||
"indentWidth": 4,
|
||||
"lineWidth": 120,
|
||||
"quoteProperties": "asNeeded",
|
||||
"quoteStyle": "single",
|
||||
"semicolons": "asNeeded",
|
||||
"trailingCommas": "all"
|
||||
}
|
||||
},
|
||||
"files": {
|
||||
"ignoreUnknown": true,
|
||||
"include": ["*.js", "*.json", "*.ts", "*.tsx", "*.jsx", "*.mjs"],
|
||||
"ignore": ["dist/**/*", "node_modules/**/*"]
|
||||
}
|
||||
}
|
||||
10
lib/init/package.json
Normal file
10
lib/init/package.json
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"name": "@revenge-mod/init",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": {
|
||||
"default": "./src/index.ts"
|
||||
}
|
||||
}
|
||||
}
|
||||
75
lib/init/src/index.ts
Normal file
75
lib/init/src/index.ts
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
import './patches/prevent-immutablize'
|
||||
import './patches/proxy'
|
||||
|
||||
import { getErrorStack } from '@revenge-mod/utils/errors'
|
||||
|
||||
import { logger } from './shared'
|
||||
|
||||
import type { Metro } from '@revenge-mod/modules'
|
||||
|
||||
let metroRequire: Metro.RequireFn | undefined = globalThis.__r
|
||||
let metroDefine: Metro.DefineFn | undefined = globalThis.__d
|
||||
|
||||
Object.defineProperties(globalThis, {
|
||||
__r: {
|
||||
configurable: true,
|
||||
get: () => metroRequire,
|
||||
set: originalMetroRequire => {
|
||||
metroRequire = id =>
|
||||
id
|
||||
? // Early modules (React, React Native, polyfills, etc.) are required even before index (module 0) is required
|
||||
originalMetroRequire(id)
|
||||
: // Once module 0 is required, we initialize our patches
|
||||
// We also revert __r to its original value, for performance reasons
|
||||
// biome-ignore lint/performance/noDelete: This is faster than using Object.defineProperty
|
||||
(delete globalThis.__r, (globalThis.__r = originalMetroRequire), onceIndexModuleRequired())
|
||||
},
|
||||
},
|
||||
__d: {
|
||||
configurable: true,
|
||||
// __d() is used to define a module
|
||||
// Before the first module is being defined, we clear the modules list (so we can get the module list instance)
|
||||
// We also revert __d to its original value, for performance reasons
|
||||
get: () => {
|
||||
// biome-ignore lint/performance/noDelete: This is faster than using Object.defineProperty
|
||||
delete globalThis.__d
|
||||
globalThis.__d = metroDefine
|
||||
|
||||
modules = __c!()
|
||||
return metroDefine
|
||||
},
|
||||
set: v => {
|
||||
metroDefine = v
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
export let modules: Metro.ModuleList
|
||||
|
||||
function onceIndexModuleRequired() {
|
||||
if (!__BUILD_FLAG_INIT_DISABLE_PATCH_LOG_PROMISE_REJECTIONS__) require('./patches/log-promise-rejections')
|
||||
|
||||
initialize().catch(e => {
|
||||
const { ClientInfoModule, DeviceModule } = require('@revenge-mod/modules/native')
|
||||
|
||||
alert(
|
||||
[
|
||||
'Failed to load Revenge!',
|
||||
'',
|
||||
`Discord: ${ClientInfoModule.Version} (${ClientInfoModule.Build})`,
|
||||
`Device: ${DeviceModule.deviceManufacturer} ${DeviceModule.deviceModel}`,
|
||||
'',
|
||||
getErrorStack(e),
|
||||
].join('\n'),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
! This function is blocking app startup !
|
||||
We need to make sure it's as fast as possible
|
||||
*/
|
||||
async function initialize() {
|
||||
logger.log('Revenge loaded!')
|
||||
__r(0)
|
||||
}
|
||||
23
lib/init/src/patches/log-promise-rejections.ts
Normal file
23
lib/init/src/patches/log-promise-rejections.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* Hermes doesn't natively support Promises, it instead has a polyfill for it.
|
||||
* It doesn't throw and never logs rejections in production, so we are patching it to catch errors when using async functions.
|
||||
*
|
||||
* See for reference: https://github.com/facebook/hermes/blob/3332fa020cae0bab751f648db7c94e1d687eeec7/lib/InternalBytecode/01-Promise.js#L446
|
||||
*/
|
||||
|
||||
import { getErrorStack } from '@revenge-mod/utils/errors'
|
||||
|
||||
import { logger } from '../shared'
|
||||
|
||||
const ErrorTypeWhitelist = [ReferenceError, TypeError, RangeError]
|
||||
|
||||
Promise._m = (promise, err) => {
|
||||
if (err)
|
||||
setTimeout(
|
||||
() => {
|
||||
if (promise._h === 0) logger.error(`Unhandled promise rejection: ${getErrorStack(err)}`)
|
||||
},
|
||||
ErrorTypeWhitelist.some(it => err instanceof it) ? 0 : 2000,
|
||||
// The time is completely arbitary. I've picked what Hermes chose.
|
||||
)
|
||||
}
|
||||
8
lib/init/src/patches/prevent-immutablize.ts
Normal file
8
lib/init/src/patches/prevent-immutablize.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
/**
|
||||
* This patch prevents objects from being made immutable.
|
||||
*/
|
||||
|
||||
// Retain reference to the functions so the actual functions can be used later
|
||||
import '@revenge-mod/utils/functions'
|
||||
|
||||
Object.freeze = Object.seal = Object.preventExtensions = o => o
|
||||
18
lib/init/src/patches/proxy.ts
Normal file
18
lib/init/src/patches/proxy.ts
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
/**
|
||||
* This patch allows us to store instances of Proxy, so we can check whether a value is created using Proxy or not.
|
||||
* This is especially useful for blacklisting discord-intl modules exports, and exports that cannot be patched.
|
||||
*/
|
||||
|
||||
export const _instances = new WeakSet<object>()
|
||||
// export const _targets = new WeakMap<object, object>()
|
||||
|
||||
const OriginalProxy = globalThis.Proxy
|
||||
globalThis.Proxy = new Proxy(OriginalProxy, {
|
||||
construct(_target, args) {
|
||||
// @ts-expect-error
|
||||
const prox = new OriginalProxy(...args)
|
||||
_instances.add(prox)
|
||||
// _targets.set(prox, args[0])
|
||||
return prox
|
||||
},
|
||||
})
|
||||
3
lib/init/src/shared.ts
Normal file
3
lib/init/src/shared.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
import { createLogger } from '@revenge-mod/utils/logger'
|
||||
|
||||
export const logger = createLogger('revenge.init')
|
||||
19
lib/utils/package.json
Normal file
19
lib/utils/package.json
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"name": "@revenge-mod/utils",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"exports": {
|
||||
"./errors": {
|
||||
"default": "./src/errors.ts"
|
||||
},
|
||||
"./functions": {
|
||||
"default": "./src/functions.ts"
|
||||
},
|
||||
"./logger": {
|
||||
"default": "./src/logger.ts"
|
||||
},
|
||||
"./types": {
|
||||
"types": "./src/types.d.ts"
|
||||
}
|
||||
}
|
||||
}
|
||||
3
lib/utils/src/errors.ts
Normal file
3
lib/utils/src/errors.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
export function getErrorStack(e: unknown) {
|
||||
return e instanceof Error ? e.stack : String(e)
|
||||
}
|
||||
5
lib/utils/src/functions.ts
Normal file
5
lib/utils/src/functions.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
// This file is imported before the functions are modified
|
||||
|
||||
export const objectFreeze = Object.freeze
|
||||
export const objectSeal = Object.seal
|
||||
export const objectPreventExtensions = Object.preventExtensions
|
||||
35
lib/utils/src/logger.ts
Normal file
35
lib/utils/src/logger.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
export function createLogger(tag: string) {
|
||||
return {
|
||||
log: (message: string) => console.log(`[${tag}] ${message}`),
|
||||
warn: (message: string) => console.warn(`[${tag}] ${message}`),
|
||||
error: (message: string) => console.error(`[${tag}] ${message}`),
|
||||
wtf: (message: string) => console.error(`\u001b[31m[${tag}] ${message}\u001b[0m`),
|
||||
} satisfies BasicLogger
|
||||
}
|
||||
|
||||
export interface BasicLogger {
|
||||
/**
|
||||
* Log a message to the console.
|
||||
*/
|
||||
log(...args: unknown[]): void
|
||||
/**
|
||||
* Log a warning message to the console.
|
||||
*
|
||||
* On Android, this will print to logcat with the `WARN` level.
|
||||
*/
|
||||
warn(...args: unknown[]): void
|
||||
/**
|
||||
* Log an error message to the console.
|
||||
*
|
||||
* On Android, this will print to logcat with the `ERROR` level.
|
||||
*/
|
||||
error(...args: unknown[]): void
|
||||
/**
|
||||
* [*What a Terrible Failure!*](https://developer.android.com/reference/android/util/Log#wtf(java.lang.String,%20java.lang.String))
|
||||
*
|
||||
* Log an error message to the console in red (ANSI)
|
||||
*
|
||||
* On Android, this will print to logcat with the `ERROR` level.
|
||||
*/
|
||||
wtf(...args: unknown[]): void
|
||||
}
|
||||
13
lib/utils/src/proxy.ts
Normal file
13
lib/utils/src/proxy.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
import { _instances /* _targets */ } from '../../init/src/patches/proxy'
|
||||
|
||||
/**
|
||||
* Returns whether the object is a proxy
|
||||
* @param obj The object to check
|
||||
*/
|
||||
export function isProxy(obj: object) {
|
||||
return _instances.has(obj)
|
||||
}
|
||||
|
||||
// export function getProxyTarget(obj: object) {
|
||||
// return _targets.get(obj)
|
||||
// }
|
||||
3
lib/utils/src/types.d.ts
vendored
Normal file
3
lib/utils/src/types.d.ts
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
export type Nullish = null | undefined
|
||||
export type If<T, Then, Else> = T extends true ? Then : Else
|
||||
export type AnyObject = Record<any, any>
|
||||
26
package.json
Normal file
26
package.json
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"name": "@revenge-mod/revenge",
|
||||
"private": true,
|
||||
"module": "src/index.ts",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "bun --bun run scripts/build.ts",
|
||||
"dev": "bun --bun run scripts/dev.ts"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "^1.9.4",
|
||||
"@parcel/watcher": "^2.5.1",
|
||||
"@swc/core": "^1.11.9",
|
||||
"@types/bun": "latest",
|
||||
"@unbound-mod/hermesc": "^1.0.3",
|
||||
"buffer": "^6.0.3",
|
||||
"chalk": "^5.4.1",
|
||||
"react-native": "^0.77.1",
|
||||
"rolldown": "^1.0.0-beta.4-commit.beda261"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^5.7.3"
|
||||
},
|
||||
"workspaces": ["lib/*", "plugins/*"],
|
||||
"trustedDependencies": ["@biomejs/biome", "@parcel/watcher", "@swc/core"]
|
||||
}
|
||||
145
scripts/build.ts
Normal file
145
scripts/build.ts
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
import { transform } from '@swc/core'
|
||||
import { main } from 'bun'
|
||||
import chalk from 'chalk'
|
||||
import { type OutputChunk, type RolldownPlugin, rolldown } from 'rolldown'
|
||||
|
||||
// If this file is being run directly, build the project
|
||||
if (main === import.meta.filename) build()
|
||||
|
||||
export default async function build(dev = false, log = true) {
|
||||
const start = performance.now()
|
||||
|
||||
const bundle = await rolldown({
|
||||
input: 'src/index.ts',
|
||||
platform: 'neutral',
|
||||
treeshake: true,
|
||||
keepNames: true,
|
||||
moduleTypes: {
|
||||
'.webp': 'dataurl',
|
||||
},
|
||||
define: {
|
||||
__BUILD_COMMIT__: JSON.stringify(''),
|
||||
__BUILD_ENV__: JSON.stringify(dev ? 'development' : 'production'),
|
||||
__BUILD_FLAG_INIT_DISABLE_PATCH_LOG_PROMISE_REJECTIONS__: String(!dev),
|
||||
},
|
||||
plugins: [
|
||||
swcPlugin(),
|
||||
hermesCPlugin({
|
||||
flags: [
|
||||
dev ? '-Og' : '-O',
|
||||
'-eager',
|
||||
'-finline',
|
||||
'-fno-static-require',
|
||||
'-Wno-direct-eval',
|
||||
'-Wno-undefined-variable',
|
||||
],
|
||||
afterComplete() {
|
||||
if (log) console.debug(chalk.gray('\u{1F5CE} Bytecode compilation finished'))
|
||||
},
|
||||
}),
|
||||
],
|
||||
})
|
||||
|
||||
await bundle.write({
|
||||
file: 'dist/revenge.js',
|
||||
format: 'iife',
|
||||
footer: '//# sourceURL=Revenge',
|
||||
inlineDynamicImports: true,
|
||||
})
|
||||
|
||||
if (log)
|
||||
console.info(
|
||||
chalk.greenBright(
|
||||
`\u{1F5CE} Compiled successfully! ${chalk.gray(`(took ${(performance.now() - start).toFixed(2)}ms)`)}`,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
function swcPlugin() {
|
||||
return {
|
||||
name: 'swc',
|
||||
transform: {
|
||||
filter: {
|
||||
id: /\.[cm]?[jt]sx?$/,
|
||||
},
|
||||
handler(code) {
|
||||
return transform(code, {
|
||||
jsc: {
|
||||
transform: {
|
||||
react: {
|
||||
runtime: 'automatic',
|
||||
},
|
||||
},
|
||||
parser: {
|
||||
syntax: 'typescript',
|
||||
tsx: true,
|
||||
},
|
||||
},
|
||||
env: {
|
||||
// https://github.com/discord/hermes/blob/main/doc/Features.md
|
||||
targets: 'fully supports es6',
|
||||
include: [
|
||||
'transform-block-scoping',
|
||||
'transform-classes',
|
||||
'transform-async-to-generator',
|
||||
'transform-async-generator-functions',
|
||||
'transform-named-capturing-groups-regex',
|
||||
],
|
||||
exclude: [
|
||||
'transform-parameters',
|
||||
'transform-template-literals',
|
||||
'transform-exponentiation-operator',
|
||||
'transform-nullish-coalescing-operator',
|
||||
'transform-object-rest-spread',
|
||||
'transform-optional-chaining',
|
||||
'transform-logical-assignment-operators',
|
||||
],
|
||||
},
|
||||
})
|
||||
},
|
||||
},
|
||||
} satisfies RolldownPlugin
|
||||
}
|
||||
|
||||
function hermesCPlugin({ afterComplete, flags }: { flags?: string[]; afterComplete?: () => void } = {}) {
|
||||
const paths = {
|
||||
win32: 'hermesc.exe',
|
||||
darwin: 'darwin/hermesc',
|
||||
linux: 'linux/hermesc',
|
||||
}
|
||||
|
||||
if (!(process.platform in paths)) throw new Error(`Unsupported platform: ${process.platform}`)
|
||||
|
||||
const binPath = paths[process.platform as keyof typeof paths]
|
||||
|
||||
return {
|
||||
name: 'hermesc',
|
||||
generateBundle(_, bundle) {
|
||||
const file = bundle['revenge.js'] as OutputChunk
|
||||
if (!file || !file.code) throw new Error('No code to compile')
|
||||
|
||||
const cmd = Bun.spawnSync(
|
||||
[
|
||||
`./node_modules/@unbound-mod/hermesc/${process.platform}/${binPath}`,
|
||||
'-emit-binary',
|
||||
...(flags ?? []),
|
||||
],
|
||||
{
|
||||
stdin: new Blob([file.code]),
|
||||
stdout: 'pipe',
|
||||
},
|
||||
)
|
||||
|
||||
const buf = cmd.stdout
|
||||
if (!buf.length) throw new Error('No output from hermesc')
|
||||
|
||||
this.emitFile({
|
||||
type: 'asset',
|
||||
fileName: `${file.fileName.split('.')[0]!}.bundle`,
|
||||
source: buf,
|
||||
})
|
||||
|
||||
if (afterComplete) afterComplete()
|
||||
},
|
||||
} satisfies RolldownPlugin
|
||||
}
|
||||
51
scripts/dev.ts
Normal file
51
scripts/dev.ts
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
import { join } from 'path'
|
||||
import watcher from '@parcel/watcher'
|
||||
import chalk from 'chalk'
|
||||
import build from './build'
|
||||
|
||||
const cwdify = (path: string) => join(process.cwd(), path)
|
||||
|
||||
const Sources = ['src', 'lib', 'plugins'].map(cwdify)
|
||||
const ExitTriggers = ['scripts', 'package.json', 'bun.lock'].map(cwdify)
|
||||
|
||||
function debounce<F extends (...args: any[]) => any>(func: F, timeout: number) {
|
||||
let timer: NodeJS.Timer
|
||||
return (...args: Parameters<F>) =>
|
||||
new Promise(rs => {
|
||||
clearTimeout(timer)
|
||||
timer = setTimeout(() => {
|
||||
rs(func(...args))
|
||||
}, timeout)
|
||||
})
|
||||
}
|
||||
|
||||
const buildDevWithDebounceAndCatchErrors = debounce(async () => {
|
||||
try {
|
||||
return await build(true)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}, 250)
|
||||
|
||||
watcher.subscribe(process.cwd(), async (err, events) => {
|
||||
if (err) return console.error(err)
|
||||
|
||||
if (events.some(it => ExitTriggers.some(se => it.path.startsWith(se)))) {
|
||||
console.error(chalk.redBright('\u26A0 Scripts or packages has changed, exiting!'))
|
||||
process.exit()
|
||||
}
|
||||
|
||||
if (events.some(it => Sources.some(src => it.path.startsWith(src)))) await buildDevWithDebounceAndCatchErrors()
|
||||
})
|
||||
|
||||
const server = Bun.serve({
|
||||
fetch(req, srv) {
|
||||
console.debug(chalk.gray(`\u{1F79B} Receiving request from ${srv.requestIP(req)!.address}`))
|
||||
return new Response(Bun.file('./dist/revenge.bundle'))
|
||||
},
|
||||
port: 4040,
|
||||
})
|
||||
|
||||
console.info(chalk.cyanBright(`\u24D8 Serving on port ${server.port}`))
|
||||
|
||||
await buildDevWithDebounceAndCatchErrors()
|
||||
1
src/index.ts
Normal file
1
src/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
import '@revenge-mod/init'
|
||||
28
tsconfig.json
Normal file
28
tsconfig.json
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
// Enable latest features
|
||||
"lib": ["ESNext", "DOM"],
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"moduleDetection": "force",
|
||||
"jsx": "react-jsx",
|
||||
"allowJs": true,
|
||||
|
||||
// Bundler mode
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"noEmit": true,
|
||||
|
||||
// Best practices
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
|
||||
// Some stricter flags (disabled by default)
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"noPropertyAccessFromIndexSignature": false
|
||||
},
|
||||
"exclude": ["scripts/**"]
|
||||
}
|
||||
107
types.d.ts
vendored
Normal file
107
types.d.ts
vendored
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
// All of these typings are exported, be careful what you export here!
|
||||
|
||||
import type { ErrorUtils as RNErrorUtils } from 'react-native'
|
||||
|
||||
/// HERMES
|
||||
|
||||
declare global {
|
||||
declare function setTimeout(cb: (...args: unknown[]) => unknown, timeout?: number): number
|
||||
/**
|
||||
* Calls the garbage collector
|
||||
*/
|
||||
declare function gc(): void
|
||||
|
||||
interface HermesInternalObject {
|
||||
getRuntimeProperties(): Record<string, string>
|
||||
// biome-ignore lint/complexity/noBannedTypes: You can pass any function here
|
||||
getFunctionLocation(fn: Function): {
|
||||
fileName: string
|
||||
lineNumber: number
|
||||
columnNumber: number
|
||||
segmentID: number
|
||||
virtualOffset: number
|
||||
isNative: boolean
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// HERMES PROMISES
|
||||
|
||||
declare global {
|
||||
interface Promise {
|
||||
/// PROMISE POLYFILLS FROM: https://github.com/then/promise
|
||||
/// AND: https://github.com/facebook/hermes/blob/main/lib/InternalBytecode/01-Promise.js
|
||||
_h: 0 | 1 | 2
|
||||
}
|
||||
|
||||
type HermesPromiseRejectionHandler = (promise: Promise<any>, error: any) => void
|
||||
|
||||
interface PromiseConstructor {
|
||||
_m: HermesPromiseRejectionHandler
|
||||
}
|
||||
}
|
||||
|
||||
/// REACT DEVTOOLS
|
||||
|
||||
declare global {
|
||||
var __REACT_DEVTOOLS_GLOBAL_HOOK__: unknown | undefined
|
||||
var __reactDevTools:
|
||||
| {
|
||||
version: string
|
||||
exports: {
|
||||
connectToDevTools(opts: {
|
||||
host?: string
|
||||
port?: number
|
||||
websocket?: WebSocket
|
||||
}): void
|
||||
}
|
||||
}
|
||||
| undefined
|
||||
}
|
||||
|
||||
/// METRO
|
||||
|
||||
declare global {
|
||||
var nativeModuleProxy: Record<string, unknown>
|
||||
var __r: Metro.RequireFn
|
||||
var __c: Metro.ClearFn
|
||||
var __d: Metro.DefineFn
|
||||
}
|
||||
|
||||
/// REACT NATIVE
|
||||
|
||||
declare global {
|
||||
declare function nativeLoggingHook(str: string, level: number): void
|
||||
declare function alert(message: unknown): void
|
||||
|
||||
var nativePerformanceNow: typeof performance.now
|
||||
var performance: {
|
||||
now(): number
|
||||
}
|
||||
|
||||
var globalEvalWithSourceUrl: (code: string, sourceURL: string) => any
|
||||
|
||||
const ErrorUtils: RNErrorUtils
|
||||
}
|
||||
|
||||
export namespace ReactNativeInternals {
|
||||
namespace AssetsRegistry {
|
||||
// export type AssetDestPathResolver = 'android' | 'generic'
|
||||
|
||||
export type PackagerAsset = {
|
||||
__packager_asset: boolean
|
||||
fileSystemLocation?: string
|
||||
httpServerLocation?: string
|
||||
width?: number
|
||||
height?: number
|
||||
scales: number[]
|
||||
hash: string
|
||||
name: string
|
||||
type: string
|
||||
// resolver?: AssetDestPathResolver
|
||||
}
|
||||
|
||||
export function registerAsset(asset: PackagerAsset): number
|
||||
export function getAssetByID(assetId: number): PackagerAsset
|
||||
}
|
||||
}
|
||||
16
types.internal.d.ts
vendored
Normal file
16
types.internal.d.ts
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// Type definitions for things in this codebase ONLY!
|
||||
|
||||
import type { Buffer as _Buffer } from 'buffer'
|
||||
import type MessageQueue from 'react-native/Libraries/BatchedBridge/MessageQueue'
|
||||
|
||||
declare global {
|
||||
// Discord has a Buffer polyfill that gets initialized a little later, be careful with this
|
||||
var Buffer: typeof _Buffer
|
||||
}
|
||||
|
||||
declare global {
|
||||
const __BUILD_ENV__: 'development' | 'production'
|
||||
const __BUILD_COMMIT__: string
|
||||
|
||||
const __BUILD_FLAG_INIT_DISABLE_PATCH_LOG_PROMISE_REJECTIONS__: boolean
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue