@mirid-dev/sendkit 0.0.0-stage → 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from "commander";
3
+ import { sendTelegramMessage, telegramMessageInputSchema, telegramMessageOptionsSchema } from "@mirid-dev/sendkit-core";
4
+ import { z } from "zod";
5
+ import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
6
+ import { homedir } from "node:os";
7
+ import { dirname, join } from "node:path";
8
+ // src/config.ts
9
+ const configPath = join(homedir(), ".config", "sendkit", "config.json");
10
+ const botTokenSchema = telegramMessageOptionsSchema.shape.botToken;
11
+ const cliConfigSchema = z.object({ telegramBotToken: botTokenSchema.optional() });
12
+ function writeTelegramBotToken(token) {
13
+ mkdirSync(dirname(configPath), { recursive: true });
14
+ writeFileSync(configPath, `${JSON.stringify({ telegramBotToken: token }, null, 2)}\n`, { mode: 384 });
15
+ chmodSync(configPath, 384);
16
+ }
17
+ function readCliConfig() {
18
+ try {
19
+ return cliConfigSchema.parse(JSON.parse(readFileSync(configPath, "utf8")));
20
+ } catch (error) {
21
+ throw new Error(`Invalid config at ${configPath}. Run \`sendkit init\` again.`, { cause: error });
22
+ }
23
+ }
24
+ function getTelegramBotToken() {
25
+ if (!existsSync(configPath)) throw new Error("Telegram bot token is required. Run `sendkit init`.");
26
+ const token = readCliConfig().telegramBotToken;
27
+ if (!token) throw new Error("Telegram bot token is required. Run `sendkit init`.");
28
+ return token;
29
+ }
30
+ // src/input.ts
31
+ function promptHidden(prompt) {
32
+ const { stdin, stdout } = process;
33
+ return new Promise((resolve, reject) => {
34
+ let value = "";
35
+ const finish = (error) => {
36
+ stdin.off("data", onData);
37
+ stdin.setRawMode(false);
38
+ stdin.pause();
39
+ stdout.write("\n");
40
+ if (error) reject(error);
41
+ else resolve(value);
42
+ };
43
+ const onData = (chunk) => {
44
+ for (const char of chunk) {
45
+ if (char === "\r" || char === "\n") return finish();
46
+ if (char === "") return finish(/* @__PURE__ */ new Error("Cancelled"));
47
+ if (char === "" || char === "\b") value = value.slice(0, -1);
48
+ else value += char;
49
+ }
50
+ };
51
+ stdout.write(prompt);
52
+ stdin.setRawMode(true);
53
+ stdin.setEncoding("utf8");
54
+ stdin.on("data", onData);
55
+ stdin.resume();
56
+ });
57
+ }
58
+ async function readStdin() {
59
+ const chunks = [];
60
+ for await (const chunk of process.stdin) chunks.push(Buffer.from(chunk));
61
+ return Buffer.concat(chunks).toString("utf8");
62
+ }
63
+ function readTelegramBotTokenInput() {
64
+ return process.stdin.isTTY ? promptHidden("Telegram bot token: ") : readStdin();
65
+ }
66
+ // src/index.ts
67
+ const program = new Command();
68
+ program.name("sendkit").description("SendKit CLI backed by sendkit-core");
69
+ program.command("init").description("Configure SendKit CLI local settings").option("--telegram-bot-token <botToken>", "Telegram bot token (prompted for, or read from stdin, when omitted)").action(async (options) => {
70
+ const token = botTokenSchema.safeParse(options.telegramBotToken ?? await readTelegramBotTokenInput());
71
+ if (!token.success) {
72
+ for (const issue of token.error.issues) console.error(`Invalid Telegram bot token: ${issue.message}`);
73
+ process.exit(1);
74
+ }
75
+ writeTelegramBotToken(token.data);
76
+ console.log(`Saved SendKit CLI config to ${configPath}`);
77
+ });
78
+ program.enablePositionalOptions().command("telegram").description("Send a Telegram message").argument("<chatId>", "Telegram Chat ID").argument("<message>", "Message text to send").passThroughOptions().action(async (chatId, message) => {
79
+ const args = telegramMessageInputSchema.safeParse({
80
+ chatId,
81
+ message
82
+ });
83
+ if (!args.success) {
84
+ for (const issue of args.error.issues) console.error(`Invalid ${issue.path.join(".")}: ${issue.message}`);
85
+ process.exit(1);
86
+ }
87
+ const botToken = getTelegramBotToken();
88
+ console.log(`Sending message to ${args.data.chatId}...`);
89
+ const result = await sendTelegramMessage({
90
+ ...args.data,
91
+ botToken
92
+ });
93
+ console.log("Message sent");
94
+ console.log(` Message ID: ${result.messageId}`);
95
+ console.log(` Chat ID: ${result.chatId}`);
96
+ console.log(` Sent at: ${result.sentAt.toLocaleString()}`);
97
+ });
98
+ await program.parseAsync(process.argv).catch((error) => {
99
+ console.error(error instanceof Error ? error.message : String(error));
100
+ process.exitCode = 1;
101
+ });
102
+ export {};
103
+
104
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/config.ts","../src/input.ts","../src/index.ts"],"sourcesContent":["import { z } from 'zod'\nimport { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { dirname, join } from 'node:path'\nimport { telegramMessageOptionsSchema } from '@mirid-dev/sendkit-core'\n\nexport const configPath = join(homedir(), '.config', 'sendkit', 'config.json')\nexport const botTokenSchema = telegramMessageOptionsSchema.shape.botToken\n\nconst cliConfigSchema = z.object({\n telegramBotToken: botTokenSchema.optional(),\n})\n\nexport function writeTelegramBotToken(token: string) {\n mkdirSync(dirname(configPath), { recursive: true })\n writeFileSync(configPath, `${JSON.stringify({ telegramBotToken: token }, null, 2)}\\n`, {\n mode: 0o600,\n })\n // mode only applies when the file is created, so tighten an existing file too\n chmodSync(configPath, 0o600)\n}\n\nfunction readCliConfig() {\n try {\n return cliConfigSchema.parse(JSON.parse(readFileSync(configPath, 'utf8')))\n } catch (error) {\n // Don't surface the raw JSON/Zod error, it doesn't say which file is broken\n throw new Error(`Invalid config at ${configPath}. Run \\`sendkit init\\` again.`, {\n cause: error,\n })\n }\n}\n\nexport function getTelegramBotToken() {\n if (!existsSync(configPath)) {\n throw new Error('Telegram bot token is required. Run `sendkit init`.')\n }\n\n const token = readCliConfig().telegramBotToken\n\n if (!token) {\n throw new Error('Telegram bot token is required. Run `sendkit init`.')\n }\n\n return token\n}\n","// Read hidden input from a terminal, so the token isn't echoed to the screen\nfunction promptHidden(prompt: string) {\n const { stdin, stdout } = process\n\n return new Promise<string>((resolve, reject) => {\n let value = ''\n\n const finish = (error?: Error) => {\n stdin.off('data', onData)\n stdin.setRawMode(false)\n stdin.pause()\n stdout.write('\\n')\n\n if (error) {\n reject(error)\n } else {\n resolve(value)\n }\n }\n\n const onData = (chunk: string) => {\n for (const char of chunk) {\n if (char === '\\r' || char === '\\n') {\n return finish()\n }\n if (char === '\\u0003') {\n return finish(new Error('Cancelled'))\n }\n if (char === '\\u007f' || char === '\\b') {\n value = value.slice(0, -1)\n } else {\n value += char\n }\n }\n }\n\n stdout.write(prompt)\n stdin.setRawMode(true)\n stdin.setEncoding('utf8')\n stdin.on('data', onData)\n stdin.resume()\n })\n}\n\nasync function readStdin() {\n const chunks: Buffer[] = []\n\n for await (const chunk of process.stdin) {\n chunks.push(Buffer.from(chunk))\n }\n\n return Buffer.concat(chunks).toString('utf8')\n}\n\n// Passing the token as a flag leaves it in shell history and `ps`, so prompt or read stdin by default\nexport function readTelegramBotTokenInput() {\n return process.stdin.isTTY ? promptHidden('Telegram bot token: ') : readStdin()\n}\n","#!/usr/bin/env node\nimport { Command } from 'commander'\nimport { sendTelegramMessage, telegramMessageInputSchema } from '@mirid-dev/sendkit-core'\nimport { botTokenSchema, configPath, getTelegramBotToken, writeTelegramBotToken } from './config'\nimport { readTelegramBotTokenInput } from './input'\n\nconst program = new Command()\n\nprogram.name('sendkit').description('SendKit CLI backed by sendkit-core')\n\nprogram\n .command('init')\n .description('Configure SendKit CLI local settings')\n .option(\n '--telegram-bot-token <botToken>',\n 'Telegram bot token (prompted for, or read from stdin, when omitted)',\n )\n .action(async (options: { telegramBotToken?: string }) => {\n const token = botTokenSchema.safeParse(\n options.telegramBotToken ?? (await readTelegramBotTokenInput()),\n )\n\n if (!token.success) {\n for (const issue of token.error.issues) {\n console.error(`Invalid Telegram bot token: ${issue.message}`)\n }\n process.exit(1)\n }\n\n writeTelegramBotToken(token.data)\n console.log(`Saved SendKit CLI config to ${configPath}`)\n })\n\nprogram\n // Required by passThroughOptions() on the subcommand below\n .enablePositionalOptions()\n .command('telegram')\n .description('Send a Telegram message')\n .argument('<chatId>', 'Telegram Chat ID')\n .argument('<message>', 'Message text to send')\n // Stop parsing options after <chatId>, so a message like \"-hello\" or \"--help\" is sent as text\n .passThroughOptions()\n .action(async (chatId: string, message: string) => {\n // Validate here so bad arguments print a readable message instead of a raw ZodError\n const args = telegramMessageInputSchema.safeParse({ chatId, message })\n\n if (!args.success) {\n for (const issue of args.error.issues) {\n console.error(`Invalid ${issue.path.join('.')}: ${issue.message}`)\n }\n process.exit(1)\n }\n\n // Load the token only after the arguments are valid, so argument errors aren't hidden by a missing config\n const botToken = getTelegramBotToken()\n\n console.log(`Sending message to ${args.data.chatId}...`)\n\n const result = await sendTelegramMessage({ ...args.data, botToken })\n\n console.log('Message sent')\n console.log(` Message ID: ${result.messageId}`)\n console.log(` Chat ID: ${result.chatId}`)\n console.log(` Sent at: ${result.sentAt.toLocaleString()}`)\n })\n\nawait program.parseAsync(process.argv).catch((error: unknown) => {\n // Safe to print: sendTelegramMessage never puts the bot token in its errors\n console.error(error instanceof Error ? error.message : String(error))\n process.exitCode = 1\n})\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,24 @@
1
1
  {
2
2
  "name": "@mirid-dev/sendkit",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.0.0",
4
+ "bin": {
5
+ "sendkit": "./dist/index.js"
6
+ },
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "type": "module",
11
+ "publishConfig": {
12
+ "access": "public"
13
+ },
14
+ "scripts": {
15
+ "build": "tsdown",
16
+ "pack:dry": "bun run build && bun pm pack --dry-run",
17
+ "prepublishOnly": "bun run build"
18
+ },
19
+ "dependencies": {
20
+ "@mirid-dev/sendkit-core": "0.0.0",
21
+ "commander": "^15.0.0",
22
+ "zod": "^4.6.7"
23
+ }
24
+ }
package/README.md DELETED
@@ -1,3 +0,0 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.