merge n progress

This commit is contained in:
Jacob Nguyen
2024-04-11 18:59:05 -05:00
8 changed files with 88 additions and 101 deletions

View File

@@ -3,11 +3,11 @@
</div>
# Features
😁 **User Friendly** <br>
💦 **Simple** <br>
🌱 **Efficient** <br>
💪 **Powerful** <br>
- Manage discord application commands from the command line.
- Install plugins from the community.
- Really fast startup times (I think).
- Deploy with premade docker configurations.
- Inhouse build tool based on esbuild built for sern applications, nearly **zero** config.
## Installation

View File

@@ -4,7 +4,6 @@ import p from 'node:path';
import { glob } from 'glob';
import { configDotenv } from 'dotenv';
import assert from 'node:assert';
import { imageLoader, validExtensions } from '../plugins/imageLoader';
import defaultEsbuild from '../utilities/defaultEsbuildConfig';
import { require } from '../utilities/require';
import { pathExists, pathExistsSync } from 'find-up';
@@ -13,6 +12,7 @@ import * as Preprocessor from '../utilities/preprocessor';
import { bold, magentaBright } from 'colorette';
import { readFile } from 'fs/promises'
import { fileURLToPath} from 'node:url'
const validExtensions = ['.ts', '.js', '.json', '.png', '.jpg', '.jpeg', '.webp'];
type BuildOptions = {
/**
* Define __VERSION__
@@ -159,7 +159,7 @@ export async function build(options: Record<string, any>) {
console.log(commandsImports)
await esbuild.build({
entryPoints: commandsPaths.map(file => p.join("src", "commands", file)),
plugins: [imageLoader, ...(buildConfig.esbuildPlugins ?? [])],
plugins: [...(buildConfig.esbuildPlugins ?? [])],
...defaultEsbuild(buildConfig.format!, buildConfig.tsconfig, "./dist/commands"),
outdir: "./dist/commands",
dropLabels: [buildConfig.mode === 'production' ? '__DEV__' : '__PROD__', ...buildConfig.dropLabels!],
@@ -173,13 +173,13 @@ export async function build(options: Record<string, any>) {
.replace("\"use handle\";", `
${commandsPaths.map((imp, i) => {
if(i === 0) {
return `if(interaction.data.name === "${p.parse(imp).name}") {
const data = createContext(interaction)
const success = await applyPlugins(${p.parse(imp).name}, data);
if(success) {
await ${p.parse(imp).name}.execute(data);
}
}`
return `if(interaction.data.name === "${p.parse(imp).name}") {
const data = createContext(interaction)
const success = await applyPlugins(${p.parse(imp).name}, data);
if(success) {
await ${p.parse(imp).name}.execute(data);
}
}`
}
return `else if(interaction.data.name === "${p.parse(imp).name}" ) {
const data = createContext(interaction)
@@ -192,40 +192,38 @@ export async function build(options: Record<string, any>) {
await writeFile("./dist/out.js", importedModulesTemplate);
} else {
const entryPoints = await glob(`./src/**/*{${validExtensions.join(',')}}`, {
//for some reason, my ignore glob wasn't registering correctly'
ignore: {
ignored: (p) => p.name.endsWith('.d.ts'),
},
});
try {
const defVersion = () => JSON.stringify(packageJson().version);
const define = {
...(buildConfig.define ?? {}),
__DEV__: `${buildConfig.mode === 'development'}`,
__PROD__: `${buildConfig.mode === 'production'}`,
} satisfies Record<string, string>;
buildConfig.defineVersion && Object.assign(define, { __VERSION__: defVersion() });
await Preprocessor.writeTsConfig(buildConfig.format!, sernTsConfigPath, writeFile);
await Preprocessor.writeAmbientFile(ambientFilePath, define, writeFile);
//https://esbuild.github.io/content-types/#tsconfig-json
await esbuild.build({
entryPoints,
plugins: [imageLoader, ...(buildConfig.esbuildPlugins ?? [])],
...defaultEsbuild(buildConfig.format!, buildConfig.tsconfig),
define,
dropLabels: [buildConfig.mode === 'production' ? '__DEV__' : '__PROD__', ...buildConfig.dropLabels!],
const entryPoints = await glob(`./src/**/*{${validExtensions.join(',')}}`, {
//for some reason, my ignore glob wasn't registering correctly'
ignore: {
ignored: (p) => p.name.endsWith('.d.ts'),
},
});
} catch (e) {
console.error(e);
process.exit(1);
}
try {
const defVersion = () => JSON.stringify(packageJson().version);
const define = {
...(buildConfig.define ?? {}),
__DEV__: `${buildConfig.mode === 'development'}`,
__PROD__: `${buildConfig.mode === 'production'}`,
} satisfies Record<string, string>;
buildConfig.defineVersion && Object.assign(define, { __VERSION__: defVersion() });
await Preprocessor.writeTsConfig(buildConfig.format!, sernTsConfigPath, writeFile);
await Preprocessor.writeAmbientFile(ambientFilePath, define, writeFile);
//https://esbuild.github.io/content-types/#tsconfig-json
await esbuild.build({
entryPoints,
plugins: [...(buildConfig.esbuildPlugins ?? [])],
...defaultEsbuild(buildConfig.format!, buildConfig.tsconfig),
define,
dropLabels: [buildConfig.mode === 'production' ? '__DEV__' : '__PROD__', ...buildConfig.dropLabels!],
});
} catch (e) {
console.error(e);
process.exit(1);
}
}
}

View File

@@ -14,8 +14,6 @@ export async function publish(commandDir: string | undefined, args: Partial<Publ
// assign args.import to empty array if non existent
args.import ??= [];
args.token && console.info('Token passed through command line');
args.applicationId && console.info(magentaBright('WARNING')+ ' This option is deprecated. Do not pass applicationId through command line');
commandDir && console.info('Publishing with override path: ', commandDir);
const dotenvLocation = new URL('../node_modules/dotenv/config.js', rootPath),
@@ -25,10 +23,6 @@ export async function publish(commandDir: string | undefined, args: Partial<Publ
// loader flag to require typescript files
const command = fork(fileURLToPath(publishScript), [], {
execArgv: ['--loader', esmLoader.toString(), '-r', fileURLToPath(dotenvLocation), '--no-warnings'],
env: {
token: args.token ?? '',
applicationId: args.applicationId ?? '',
},
});
// send paths object so we dont have to recalculate it in script
command.send({ config, preloads: args.import, commandDir });

View File

@@ -10,7 +10,7 @@ import { once } from 'node:events';
import * as Rest from './rest';
import type { sernConfig } from './utilities/getConfig';
import type { PublishableData, PublishableModule, Typeable } from './create-publish.d.ts';
import { cyanBright, greenBright, magentaBright, redBright } from 'colorette';
import { cyanBright, greenBright, redBright } from 'colorette';
import { inspect } from 'node:util'
import ora from 'ora';
@@ -153,6 +153,19 @@ const makePublishData = ({ commandModule, config }: Record<string, Record<string
options: optionsTransformer((commandModule?.options ?? []) as Typeable[]),
dm_permission: config?.dmPermission,
default_member_permissions: serialize(config?.defaultMemberPermissions),
//@ts-ignore
integration_types: (config?.integrationTypes ?? ['Guild']).map(
(s: string) => {
if(s === "Guild") {
return 0
} else if (s == "User") {
return 1
} else {
throw Error("IntegrationType is not one of Guild or User");
}
}),
//@ts-ignore
contexts: config?.contexts ? config.contexts : undefined
},
config,
};
@@ -160,11 +173,9 @@ const makePublishData = ({ commandModule, config }: Record<string, Record<string
// We can use these objects to publish to DAPI
const publishableData = modules.map(makePublishData),
token = process.env.token || process.env.DISCORD_TOKEN,
appid = process.env.applicationId || process.env.APPLICATION_ID;
token = process.env.token || process.env.DISCORD_TOKEN;
assert(token, 'Could not find a token for this bot in .env or commandline. Do you have DISCORD_TOKEN in env?');
appid && console.warn(`${magentaBright('WARNING')}: APPLICATION_ID is not necessary anymore`);
// partition globally published and guilded commands
const [globalCommands, guildedCommands] = publishableData.reduce(
([globals, guilded], module) => {

View File

@@ -40,7 +40,6 @@ program //
.option('-W --suppress-warnings', 'suppress experimental warning')
.option('-i, --import [scriptPath...]', 'Prerequire a script to load into publisher')
.option('-t, --token [token]')
.option('--appId [applicationId]')
.argument('[path]', 'path with respect to current working directory that will locate all published files')
.action(async (...args) => importDynamic('publish.js').then((m) => m.publish(...args)))
).addCommand(
@@ -53,6 +52,14 @@ program //
.option('-y, --yes', "Say yes to all prompts")
.option('-e, --env [path]', "Supply a path to a .env")
.action(async (...args) => importDynamic('command-clear.js').then((m) => m.commandClear(...args))));
program
.command('app')
.description('manage your discord application')
.addCommand(
new Command('update')
.description("Refresh your discord application.")
.option('-W --suppress-warnings', 'suppress experimental warning')
.action(async (...args) => importDynamic('app-update.js').then(m => m.appUpdate(...args))))
program
.command('build')

View File

@@ -1,39 +0,0 @@
import fs from 'fs/promises';
import path from 'node:path';
import { require } from '../utilities/require.js';
import { type Plugin } from 'esbuild';
import { basename } from 'node:path';
export const validExtensions = ['.ts', '.js', '.json', '.png', '.jpg', '.jpeg', '.webp'];
//https://github.com/evanw/esbuild/issues/1051
export const imageLoader = {
name: 'attachment-loader',
setup: (b) => {
const filter = new RegExp(`\.${validExtensions.slice(3).join('|')}$`);
b.onResolve({ filter }, (args) => {
//if the module is being imported, resolve the path and transform to the js stub
if (args.importer) {
const newPath = path
.format({ ...path.parse(args.path), base: '', ext: '.js' })
.split(path.sep)
.join(path.posix.sep);
return { path: newPath, namespace: 'attachment-loader', external: true };
}
// if the file is actually the attachment, resolve the full dir
return { path: require.resolve(args.path, { paths: [args.resolveDir] }), namespace: 'attachment-loader' };
});
b.onLoad({ filter: /.*/, namespace: 'attachment-loader' }, async (args) => {
const base64 = await fs.readFile(args.path).then((s) => s.toString('base64'));
return {
contents: `
var __toBuffer = (base64) => Buffer.from(base64, "base64");
module.exports = {
name: '${basename(args.path)}',
attachment: __toBuffer("${base64}")
}`,
};
});
},
} satisfies Plugin;

View File

@@ -11,7 +11,6 @@ export async function getConfig(): Promise<sernConfig> {
return output;
}
export interface sernConfig {
type?: "serverless" | "websocket"
language: 'typescript' | 'javascript';
@@ -21,5 +20,21 @@ export interface sernConfig {
commands: string;
events?: string;
};
buildPath: string;
app?: {
customInstallUrl?: string;
description?: string;
roleConnectionsVerificationUrl?: string;
installParams?: {
type: 'install params object';
};
integrationTypesConfig?: {
type: 'dictionary with keys of application integration types';
description: 'In preview. Default scopes and permissions for each supported installation context. Value for each key is an integration type configuration object';
};
flags?: number;
icon?: '?image data';
coverImage?: '?image data';
interactionsEndpointUrl?: string;
tags: string[];
}
}

View File

@@ -20,6 +20,7 @@ class JsonResponse extends Response {
super(jsonBody, init);
}
}
function createContext(rawcontext) {
return rawcontext
}
@@ -40,7 +41,7 @@ async function executeModule(
async function applyPlugins(module, payload) {
let success = true;
for (const plg of module.onEvent){
for (const plg of module.onEvent) {
const res = await plg.execute(payload);
if(!res.isOk()) {
success = false;