break up library, move bots to their own repositories
This commit is contained in:
23
packages/eve-discord/README.md
Normal file
23
packages/eve-discord/README.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# tsdown-starter
|
||||
|
||||
A starter for creating a TypeScript package.
|
||||
|
||||
## Development
|
||||
|
||||
- Install dependencies:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
- Run the unit tests:
|
||||
|
||||
```bash
|
||||
npm run test
|
||||
```
|
||||
|
||||
- Build the library:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
59
packages/eve-discord/package.json
Normal file
59
packages/eve-discord/package.json
Normal file
@@ -0,0 +1,59 @@
|
||||
{
|
||||
"name": "@star-kitten/eve-discord",
|
||||
"version": "0.0.1",
|
||||
"description": "Star Kitten EVE Discord Library.",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"homepage": "https://git.f302.me/jb/star-kitten#readme",
|
||||
"bugs": {
|
||||
"url": "https://git.f302.me/jb/star-kitten/issues"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://git.f302.me/jb/star-kitten.git"
|
||||
},
|
||||
"author": "JB <j-b-3.deviate267@passmail.net>",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./dist/index.js",
|
||||
"require": "./dist/index.js",
|
||||
"types": "./dist/index*.d.ts"
|
||||
},
|
||||
"./commands/*.js": {
|
||||
"require": "./dist/commands/*.js",
|
||||
"import": "./dist/commands/*.js",
|
||||
"types": "./dist/types/commands/*.d.ts"
|
||||
},
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@projectdysnomia/dysnomia": "github:projectdysnomia/dysnomia#dev"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bun": "^1.3.5",
|
||||
"prettier-plugin-multiline-arrays": "^4.0.3",
|
||||
"tsdown": "^0.14.2",
|
||||
"typescript": "beta"
|
||||
},
|
||||
"dependencies": {
|
||||
"@star-kitten/util": "link:@star-kitten/util",
|
||||
"@star-kitten/eve": "link:@star-kitten/eve",
|
||||
"@star-kitten/discord": "link:@star-kitten/discord"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsdown",
|
||||
"dev": "tsdown --watch",
|
||||
"link": "bun link",
|
||||
"test": "bun test",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"release": "bumpp && npm publish"
|
||||
}
|
||||
}
|
||||
136
packages/eve-discord/src/commands/appraise.command.ts
Normal file
136
packages/eve-discord/src/commands/appraise.command.ts
Normal file
@@ -0,0 +1,136 @@
|
||||
import { appraiseItems, type Appraisal } from '@star-kitten/eve/third-party/janice.js';
|
||||
import {
|
||||
componentHasIdPrefix,
|
||||
isModalLabel,
|
||||
isModalSelect,
|
||||
isModalTextInput,
|
||||
} from '@star-kitten/discord/components';
|
||||
import { createChatCommand, type CommandContext, type ExecutableInteraction, components as c, type PageContext, ButtonStyle } from '@star-kitten/discord';
|
||||
import { PageType, usePages } from '@star-kitten/discord/pages';
|
||||
import { Constants } from '@projectdysnomia/dysnomia';
|
||||
import { markets } from '@star-kitten/eve/third-party/janice.js';
|
||||
import { formatNumberToShortForm } from '@star-kitten/util';
|
||||
|
||||
|
||||
export interface AppraisalState {
|
||||
appraisal?: Appraisal;
|
||||
}
|
||||
|
||||
|
||||
function renderAppraisalModal() {
|
||||
return c.modal({ custom_id: 'appraisalResult', title: 'Appraise Items' },
|
||||
c.label({ label: 'Select a market' },
|
||||
c.stringSelect('market', { placeholder: 'Select a market', min_values: 1, max_values: 1 },
|
||||
...markets.map((m) => c.option({ label: m.name, value: m.id.toString(), default: m.id === 2 }))
|
||||
),
|
||||
),
|
||||
c.label({ label: 'Enter items to appraise' },
|
||||
c.input('input',{
|
||||
isParagraph: true,
|
||||
placeholder: `e.g. Tritanium 22222\nPyerite 8000\nMexallon 2444`,
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
function renderAppraisalFollowUp(appraisal: Appraisal,
|
||||
pageCtx: PageContext<AppraisalState>,
|
||||
interaction: ExecutableInteraction
|
||||
) {
|
||||
|
||||
const content = `
|
||||
# [Appraisal ${appraisal.id} @ ${appraisal.market.name}](https://janice.e-351.com/a/${appraisal.id})
|
||||
### Buy: \`${formatNumberToShortForm(appraisal.effectivePrices.totalBuyPrice)}\` ISK
|
||||
### Split: \`${formatNumberToShortForm(appraisal.effectivePrices.totalSplitPrice)}\` ISK
|
||||
### Sell: \`${formatNumberToShortForm(appraisal.effectivePrices.totalSellPrice)}\` ISK
|
||||
-# Volume: ${formatNumberToShortForm(appraisal.totalPackagedVolume)} m³
|
||||
\`\`\`
|
||||
Buy: Sell: Qty: Item:
|
||||
${appraisal.items.map((i) => `${formatNumberToShortForm(i.effectivePrices.buyPrice).padEnd(10)}${formatNumberToShortForm(i.effectivePrices.sellPrice).padEnd(10)}${formatNumberToShortForm(i.amount).padEnd(10)}${i.itemType.name}`).join('\n')}
|
||||
\`\`\`
|
||||
-# https://janice.e-351.com/a/${appraisal.id}
|
||||
`;
|
||||
|
||||
return c.container({ accent: 0x1da57a },
|
||||
c.text(content),
|
||||
pageCtx.state.currentPage !== 'share' && c.actionRow(
|
||||
c.button({ custom_id: 'share', label: 'Share in Channel', disabled: !interaction.channel?.id, style: ButtonStyle.PRIMARY }),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
async function execute(interaction: ExecutableInteraction, ctx: CommandContext) {
|
||||
return await usePages<AppraisalState>(
|
||||
{
|
||||
pages: {
|
||||
appraiseModal: {
|
||||
key: 'appraiseModal',
|
||||
type: PageType.MODAL,
|
||||
render: () => renderAppraisalModal(),
|
||||
},
|
||||
appraisalResult: {
|
||||
key: 'appraisalResult',
|
||||
render: async (pageCtx) => {
|
||||
if (!interaction.isModalSubmit()) {
|
||||
throw new Error('Expected a modal submit interaction for appraisalResult page');
|
||||
}
|
||||
let marketId = 2; // Default to Jita
|
||||
let items = '';
|
||||
|
||||
interaction.data.components.forEach((comp) => {
|
||||
if (isModalLabel(comp)) {
|
||||
if (isModalSelect(comp.component) && componentHasIdPrefix(comp.component, `market`)) {
|
||||
marketId = Number.parseInt(comp.component.values[0]) || marketId;
|
||||
} else if (isModalTextInput(comp.component) && componentHasIdPrefix(comp.component, `input`)) {
|
||||
items = comp.component.value || items;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const appraisal = await appraiseItems(items, marketId);
|
||||
pageCtx.state.data.appraisal = appraisal;
|
||||
return renderAppraisalFollowUp(appraisal, pageCtx, interaction);
|
||||
},
|
||||
},
|
||||
share: {
|
||||
key: 'share',
|
||||
type: PageType.FOLLOWUP,
|
||||
followUpFlags: Constants.MessageFlags.IS_COMPONENTS_V2,
|
||||
render: (pageCtx) => {
|
||||
const rendered = renderAppraisalFollowUp(pageCtx.state.data.appraisal!, pageCtx, interaction);
|
||||
return rendered;
|
||||
},
|
||||
},
|
||||
},
|
||||
initialPage: 'appraiseModal',
|
||||
timeout: 300, // 5 minutes
|
||||
ephemeral: true,
|
||||
},
|
||||
interaction,
|
||||
ctx,
|
||||
);
|
||||
}
|
||||
|
||||
export default createChatCommand({
|
||||
name: 'appraise',
|
||||
nameLocalizations: {
|
||||
de: 'bewerten',
|
||||
'es-ES': 'tasar',
|
||||
fr: 'estimer',
|
||||
ja: '査定',
|
||||
ko: '감정',
|
||||
ru: 'оценить',
|
||||
'zh-CN': '评估',
|
||||
},
|
||||
description: 'Evaluate the worth of your space junk',
|
||||
descriptionLocalizations: {
|
||||
de: 'Bewerten Sie den Wert Ihres Weltraumschrotts',
|
||||
'es-ES': 'Evalúa el valor de tu chatarra espacial',
|
||||
fr: 'Évaluez la valeur de vos déchets spatiaux',
|
||||
ja: 'あなたの宇宙のガラクタの価値を評価します',
|
||||
ko: '우주 쓰레기의 가치를 평가하십시오',
|
||||
ru: 'Оцените стоимость вашего космического мусора',
|
||||
'zh-CN': '评估您宇宙垃圾的价值',
|
||||
},
|
||||
}, execute);
|
||||
78
packages/eve-discord/src/commands/time-from-now.command.ts
Normal file
78
packages/eve-discord/src/commands/time-from-now.command.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import {
|
||||
type ExecutableInteraction,
|
||||
type CommandContext,
|
||||
createChatCommand,
|
||||
components,
|
||||
options,
|
||||
} from '@star-kitten/discord';
|
||||
|
||||
async function execute(interaction: ExecutableInteraction, context: CommandContext) {
|
||||
if (!interaction.isApplicationCommand()) return;
|
||||
|
||||
const days = (interaction.data.options.find((option) => option.name === 'days')?.value || 0) as number;
|
||||
const hours = (interaction.data.options.find((option) => option.name === 'hours')?.value || 0) as number;
|
||||
const minutes = (interaction.data.options.find((option) => option.name === 'minutes')?.value || 0) as number;
|
||||
const ephemeral = !(interaction.data.options.find((option) => option.name === 'public')?.value || false) as boolean;
|
||||
|
||||
const totalSeconds = days * 24 * 60 * 60 + hours * 60 * 60 + minutes * 60;
|
||||
|
||||
const now = new Date();
|
||||
const futureTime = new Date(now.getTime() + totalSeconds * 1000);
|
||||
|
||||
const eveTime = futureTime.toISOString().split('T')[1].split('.')[0];
|
||||
const eveDate = futureTime.toLocaleDateString(interaction.locale, {
|
||||
timeZone: 'UTC',
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: '2-digit',
|
||||
weekday: 'long',
|
||||
});
|
||||
|
||||
const discordTimestamp = Math.floor(futureTime.getTime() / 1000);
|
||||
const timestampCodes = [
|
||||
`<t:${discordTimestamp}:f>`, // Full date and time
|
||||
`<t:${discordTimestamp}:F>`, // Long date and time
|
||||
`<t:${discordTimestamp}:T>`, // 24-hour time
|
||||
`<t:${discordTimestamp}:R>`, // Relative time
|
||||
];
|
||||
|
||||
const textContent = `In ${days ? `**${days}** day${days !== 1 ? 's' : ''}, ` : ''}${hours ? `**${hours}** hour${hours !== 1 ? 's' : ''}, ` : ''}${minutes ? `**${minutes}** minute${minutes !== 1 ? 's' : ''} ` : ''}from now, the EVE time will be:
|
||||
${eveDate} at ${eveTime}
|
||||
### Discord timestamp codes:
|
||||
${timestampCodes.map((code) => `${code}\n\`\`\`${code}\`\`\``).join('\n')}
|
||||
`;
|
||||
|
||||
interaction.createMessage(
|
||||
components.componentsV2({ ephemeral }, components.container({}, components.text(textContent))),
|
||||
);
|
||||
}
|
||||
|
||||
export default createChatCommand(
|
||||
{
|
||||
name: 'time_from_now',
|
||||
description: 'Calculate time from now in EVE format with Discord timestamp codes',
|
||||
options: [
|
||||
options.numberOption({
|
||||
name: 'days',
|
||||
description: 'Number of days to add',
|
||||
required: false,
|
||||
}),
|
||||
options.numberOption({
|
||||
name: 'hours',
|
||||
description: 'Number of hours to add',
|
||||
required: false,
|
||||
}),
|
||||
options.numberOption({
|
||||
name: 'minutes',
|
||||
description: 'Number of minutes to add',
|
||||
required: false,
|
||||
}),
|
||||
options.booleanOption({
|
||||
name: 'public',
|
||||
description: 'Whether the response should be public (visible to everyone)',
|
||||
required: false,
|
||||
}),
|
||||
],
|
||||
},
|
||||
execute,
|
||||
);
|
||||
62
packages/eve-discord/src/commands/time.command.ts
Normal file
62
packages/eve-discord/src/commands/time.command.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import {
|
||||
type ExecutableInteraction,
|
||||
type CommandContext,
|
||||
Locale,
|
||||
componentsV2,
|
||||
container,
|
||||
text,
|
||||
createChatCommand,
|
||||
} from '@star-kitten/discord';
|
||||
|
||||
const eveTimeText = {
|
||||
[Locale.EN_US]: 'EVE Time',
|
||||
[Locale.EN_GB]: 'EVE Time',
|
||||
[Locale.DE]: 'EVE-Zeit',
|
||||
[Locale.ES_ES]: 'Hora EVE',
|
||||
[Locale.FR]: "Heure d'EVE",
|
||||
[Locale.JA]: 'EVE時間',
|
||||
[Locale.KO]: 'EVE 시간',
|
||||
[Locale.RU]: 'Время EVE',
|
||||
[Locale.ZH_CN]: 'EVE时间',
|
||||
};
|
||||
|
||||
async function execute(interaction: ExecutableInteraction, ctx: CommandContext) {
|
||||
if (!interaction.isApplicationCommand()) return;
|
||||
|
||||
const now = new Date();
|
||||
const eveTime = now.toISOString().split('T')[1].split('.')[0];
|
||||
const eveDate = now.toLocaleDateString(interaction.locale, {
|
||||
timeZone: 'UTC',
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: '2-digit',
|
||||
weekday: 'long',
|
||||
});
|
||||
|
||||
interaction.createMessage(componentsV2({}, container({}, text(`### ${eveTimeText[interaction.locale] || eveTimeText[Locale.EN_US]}
|
||||
${eveTime}
|
||||
${eveDate}`))));
|
||||
}
|
||||
|
||||
export default createChatCommand({
|
||||
name: 'time',
|
||||
nameLocalizations: {
|
||||
[Locale.DE]: 'zeit',
|
||||
[Locale.ES_ES]: 'hora',
|
||||
[Locale.FR]: 'heure',
|
||||
[Locale.JA]: '時間',
|
||||
[Locale.KO]: '시간',
|
||||
[Locale.RU]: 'время',
|
||||
[Locale.ZH_CN]: '时间',
|
||||
},
|
||||
description: 'Get the current EVE time',
|
||||
descriptionLocalizations: {
|
||||
[Locale.DE]: 'Holen Sie sich die aktuelle EVE-Zeit',
|
||||
[Locale.ES_ES]: 'Obtén la hora actual de EVE',
|
||||
[Locale.FR]: "Obtenez l'heure actuelle d'EVE",
|
||||
[Locale.JA]: '現在のEVE時間を取得します',
|
||||
[Locale.KO]: '현재 EVE 시간을 가져옵니다',
|
||||
[Locale.RU]: 'Получите текущее время EVE',
|
||||
[Locale.ZH_CN]: '获取当前的EVE时间',
|
||||
},
|
||||
}, execute);
|
||||
3
packages/eve-discord/src/index.ts
Normal file
3
packages/eve-discord/src/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export default function() {
|
||||
console.log('Hello from eve-discord!');
|
||||
}
|
||||
21
packages/eve-discord/tsconfig.json
Normal file
21
packages/eve-discord/tsconfig.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"strict": false,
|
||||
"noImplicitAny": false,
|
||||
"skipLibCheck": true,
|
||||
"paths": {
|
||||
"@/*": ["./src/*"],
|
||||
"@data/*": ["./data/*"],
|
||||
},
|
||||
"emitDeclarationOnly": true,
|
||||
"noEmit": false,
|
||||
"noEmitOnError": false,
|
||||
"declaration": true,
|
||||
"rootDir": ".",
|
||||
"allowImportingTsExtensions": true
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules", "build", "**/*.test.ts"]
|
||||
}
|
||||
16
packages/eve-discord/tsdown.config.ts
Normal file
16
packages/eve-discord/tsdown.config.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { defineConfig } from 'tsdown';
|
||||
|
||||
export default defineConfig([
|
||||
{
|
||||
entry: [
|
||||
'./src/**/*.ts',
|
||||
'!./src/**/*.test.ts',
|
||||
],
|
||||
platform: 'node',
|
||||
dts: true,
|
||||
minify: false,
|
||||
sourcemap: true,
|
||||
unbundle: true,
|
||||
external: ['bun:sqlite', 'bun'],
|
||||
},
|
||||
]);
|
||||
Reference in New Issue
Block a user