mirror of
https://github.com/kemko/resume.git
synced 2026-01-01 15:55:47 +03:00
chore: deps bump
This commit is contained in:
10
index.ts
10
index.ts
@@ -1,13 +1,19 @@
|
|||||||
import { generatePdf } from './utils/generatePdf';
|
import { generatePdf } from './utils/generatePdf';
|
||||||
|
import { getLogger } from './utils/logger';
|
||||||
|
|
||||||
|
const logger = getLogger("MAIN");
|
||||||
|
|
||||||
const INPUT_FILE_PATH = `${process.cwd()}/resume.md`;
|
const INPUT_FILE_PATH = `${process.cwd()}/resume.md`;
|
||||||
const OUTPUT_FILE_PATH = `${process.cwd()}/output/art_rosnovsky_software_engineer.pdf`;
|
const OUTPUT_FILE_PATH = `${process.cwd()}/output/art_rosnovsky_software_engineer.pdf`;
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
|
logger.info(`INPUT_FILE_PATH: ${INPUT_FILE_PATH}`);
|
||||||
|
logger.info(`OUTPUT_FILE_PATH: ${OUTPUT_FILE_PATH}`);
|
||||||
try {
|
try {
|
||||||
|
logger.info("Generating PDF...");
|
||||||
await generatePdf(INPUT_FILE_PATH, OUTPUT_FILE_PATH);
|
await generatePdf(INPUT_FILE_PATH, OUTPUT_FILE_PATH);
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error(`Error occurred: ${error.message}`);
|
logger.error(`Error occurred: ${error.message}`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
})
|
})()
|
||||||
|
|||||||
12
package.json
12
package.json
@@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"name": "resume-manager",
|
"name": "resume-manager",
|
||||||
"version": "1.0.1",
|
"version": "1.0.2",
|
||||||
"description": "Converts Markdown resume to PDF format.",
|
"description": "Converts Markdown resume to PDF format.",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "ts-node index.ts",
|
"build": "ts-node index.ts | pino-pretty",
|
||||||
"test": "NODE_ENV=\"test\" node --no-warnings --require \"ts-node/register\" --test **/**/*.test.ts"
|
"test": "NODE_ENV=\"test\" node --no-warnings --require \"ts-node/register\" --test **/**/*.test.ts"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
@@ -19,12 +19,14 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"markdown-pdf": "^11.0.0",
|
"markdown-pdf": "^11.0.0",
|
||||||
"md-to-pdf": "^5.2.4",
|
"md-to-pdf": "^5.2.4",
|
||||||
"typescript": "^5.2.2"
|
"pino": "^9.4.0",
|
||||||
|
"pino-pretty": "^11.2.2",
|
||||||
|
"typescript": "^5.6.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/markdown-pdf": "^9.0.5",
|
"@types/markdown-pdf": "^9.0.5",
|
||||||
"@types/node": "latest",
|
"@types/node": "^22.5.4",
|
||||||
"ts-node": "latest",
|
"ts-node": "^10.9.2",
|
||||||
"typescript": "latest"
|
"typescript": "latest"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|||||||
2986
pnpm-lock.yaml
generated
2986
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
52
resume.md
52
resume.md
@@ -8,33 +8,40 @@ pdf_options:
|
|||||||
margin: 25mm
|
margin: 25mm
|
||||||
---
|
---
|
||||||
|
|
||||||
# Art Rosnovsky
|
# Software Engineer
|
||||||
|
|
||||||
## Software Engineer
|
## Art Rosnovsky
|
||||||
|
|
||||||
> job@rosnovsky.us | [github.com/rosnovsky](https://github.com/rosnovsky) | Washington state | **Remote Only** |
|
> job@rosnovsky.us | [github.com/rosnovsky](https://github.com/rosnovsky) | Washington state | **Remote Only** |
|
||||||
|
|
||||||
Dedicated `JavaScript`/`TypeScript` Engineer with a knack for ` React`, `Kubernetes`, and CI/CD. I champion sustainable, ethical tech that makes a positive impact, by building stable, scalable, efficient, and maintainable software.
|
Dedicated `JavaScript`/`TypeScript` Engineer, passionately working with ` React`, serverless, `Kubernetes` and CI/CD. I champion sustainable, ethical tech that makes a positive impact, by building stable, scalable, efficient, and maintainable software.
|
||||||
|
|
||||||
## Technical Skills
|
## Technical Skills
|
||||||
|
|
||||||
- **Front End**: `JavaScript`, `TypeScript`, `React`, `Svelte`, `Tailwind`, `CSS`, `HTML`
|
- **Front End**: `JavaScript`, `TypeScript`, `React`, `Svelte`, `Tailwind`, `CSS`, `HTML`
|
||||||
- **Back End**: `Node.js`, `Express`, `Next.js`, `MongoDB`, `PostgreSQL`, `tRPC`, RESTful APIs
|
- **Back End**: `Node.js`, `Express`, `Next.js`, `MongoDB`, `PostgreSQL`, `tRPC`, RESTful APIs
|
||||||
- **Dev Tools/DevOps**: Git, `Docker`, `Kubernetes`, `Jira`, `AWS`, `Azure`, CI/CD (`GitHub Actions`, `Gitlab Pipelines`)
|
- **Dev Tools/DevOps**: `Git`, `Docker`, `Kubernetes`, `Jira`, `AWS`, `Azure`, `CI/CD` (`GitHub Actions`, `Gitlab Pipelines`)
|
||||||
- **Other**: former frontline reporter, can fly single-engine aircraft
|
- **Other**: former frontline reporter, can fly single-engine aircraft
|
||||||
|
|
||||||
## Work Experience
|
## Work Experience
|
||||||
|
|
||||||
|
### Senior Developer (Auth0)
|
||||||
|
> **[BeyondID](https://beyondid.com)**, Remote • Apr 2024 - Present
|
||||||
|
|
||||||
|
- Implemented end-to-end CIAM solutions for Fortune 500 companies.
|
||||||
|
- Developed and produced training materials for internal teams.
|
||||||
|
- Developed a variety of internal CIAM-related tools.
|
||||||
|
|
||||||
### Software Engineer
|
### Software Engineer
|
||||||
|
|
||||||
> **[Okta](https://okta.com)**, Remote • Mar 2021 - April 2024
|
> **[Auth0](https://auth0.com)**, Remote • Mar 2021 - April 2024
|
||||||
|
|
||||||
- Delivered the [Quarterly Snapshot](https://auth0.com/docs/get-started/tenant-settings/auth0-teams/quarterly-snapshot) feature on schedule.
|
- Delivered the [Quarterly Snapshot](https://auth0.com/docs/get-started/tenant-settings/auth0-teams/quarterly-snapshot) feature on schedule.
|
||||||
- Enhanced Technical Account Managers' workflow by building internal tools for Quarterly Snapshots covering **$20M** worth of ARR.
|
- Enhanced Technical Account Managers' workflow by building internal tools for Quarterly Snapshots covering **$20M** worth of ARR.
|
||||||
- Developed, deployed, and stabilized an internal AI/ML tool, enhancing knowledge sharing and delivery within the Customer First teams **saving over $10K** of SME productive time every year
|
- Developed, deployed, and stabilized an internal AI & ML tool, enhancing knowledge sharing and delivery within the Customer First teams **saving over $10K** of SME productive time every year.
|
||||||
- Saved **$20K** annually on AWS bills by strategically decommissioning idle resources
|
- Saved **$20K** annually on AWS bills by strategically decommissioning idle resources.
|
||||||
- Improved and delivered a multitude of high-profile company-wide internal tools
|
- Improved and delivered a multitude of high-profile company-wide internal tools.
|
||||||
- Implemented critical security improvements to key in-house Customer Success tools
|
- Implemented critical security improvements to key in-house Customer Success tools.
|
||||||
|
|
||||||
### Developer Support Engineer
|
### Developer Support Engineer
|
||||||
|
|
||||||
@@ -44,6 +51,8 @@ Dedicated `JavaScript`/`TypeScript` Engineer with a knack for ` React`, `Kuberne
|
|||||||
- Assisted hundreds of major enterprise customers with complex CIAM integration use cases.
|
- Assisted hundreds of major enterprise customers with complex CIAM integration use cases.
|
||||||
- Guided hundreds of developers through Identity Management implementations in every environment imaginable.
|
- Guided hundreds of developers through Identity Management implementations in every environment imaginable.
|
||||||
|
|
||||||
|
<div class="page-break"></div>
|
||||||
|
|
||||||
### Software Engineer
|
### Software Engineer
|
||||||
|
|
||||||
> **[Microsoft](https://microsoft.com)**, Redmond, WA • Apr 2019 - Oct 2019
|
> **[Microsoft](https://microsoft.com)**, Redmond, WA • Apr 2019 - Oct 2019
|
||||||
@@ -51,8 +60,6 @@ Dedicated `JavaScript`/`TypeScript` Engineer with a knack for ` React`, `Kuberne
|
|||||||
- Crafted both the UI and backend for an internal search application using `C#`, `.NET Core`, `MSSQL`, and `React`, scaling it from a prototype to a full-scale production app.
|
- Crafted both the UI and backend for an internal search application using `C#`, `.NET Core`, `MSSQL`, and `React`, scaling it from a prototype to a full-scale production app.
|
||||||
- Saved hundreds of hours of account managers' productive time by implementing a slick search UI and functionality
|
- Saved hundreds of hours of account managers' productive time by implementing a slick search UI and functionality
|
||||||
|
|
||||||
<div class="page-break"></div>
|
|
||||||
|
|
||||||
### Software Engineer
|
### Software Engineer
|
||||||
|
|
||||||
> **Transmark Logistics**, Kent, WA • Oct 2018 — Mar 2019
|
> **Transmark Logistics**, Kent, WA • Oct 2018 — Mar 2019
|
||||||
@@ -77,27 +84,14 @@ Dedicated `JavaScript`/`TypeScript` Engineer with a knack for ` React`, `Kuberne
|
|||||||
|
|
||||||
## Education
|
## Education
|
||||||
|
|
||||||
### Fanshawe College of Applied Art and Technology
|
- AA, Multimedia Design from [Fanshawe College of Applied Art and Technology](https://fanshawe.ca) (London, Canada)
|
||||||
|
- BA, Journalism from [RUDN University](https://rudn.ru) (Moscow, Russia)
|
||||||
> London, Canada • AA, Multimedia Design
|
- Data Foundations from [Udacity Nanodegree](https://www.udacity.com/) (Remote)
|
||||||
|
|
||||||
- Developed 'Hourglass', a student assignment management system.
|
|
||||||
- Produced a PSA for the local branch of Big Brothers Big Sisters
|
|
||||||
|
|
||||||
### RUDN University
|
|
||||||
|
|
||||||
> Moscow, Russia • BA, Journalism
|
|
||||||
|
|
||||||
- Frontline reporter for country's largest news outlets
|
|
||||||
- Reported live from significant events, including terrorist incidents.
|
|
||||||
|
|
||||||
### Udacity Nanodegree
|
|
||||||
|
|
||||||
- Data Foundations
|
|
||||||
|
|
||||||
## Languages
|
## Languages
|
||||||
|
|
||||||
- Russian — Bilingual (comprehend Belarusian, Ukrainian)
|
- English — Bilingual
|
||||||
|
- Russian — Bilingual (comprehend Ukrainian 🇺🇦, Belarusian)
|
||||||
- Arabic — Basic
|
- Arabic — Basic
|
||||||
|
|
||||||
## Publications
|
## Publications
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
|
import { getLogger } from './logger';
|
||||||
|
|
||||||
|
const logger = getLogger("fsChecks");
|
||||||
|
|
||||||
export const checkFileExists = (filePath: string) => {
|
export const checkFileExists = (filePath: string) => {
|
||||||
if (!fs.existsSync(filePath)) {
|
if (!fs.existsSync(filePath)) {
|
||||||
console.error(`File ${filePath} does not exist.`);
|
logger.error(`File ${filePath} does not exist.`);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -11,7 +14,7 @@ export const checkFileExists = (filePath: string) => {
|
|||||||
export const checkFolderExists = (folderPath: string) => {
|
export const checkFolderExists = (folderPath: string) => {
|
||||||
const folder = folderPath.split('/').slice(0, -1).join('/');
|
const folder = folderPath.split('/').slice(0, -1).join('/');
|
||||||
if (!fs.existsSync(folder)) {
|
if (!fs.existsSync(folder)) {
|
||||||
console.error(`Folder ${folder} does not exist.`);
|
logger.error(`Folder ${folder} does not exist.`);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -1,25 +1,32 @@
|
|||||||
import path from 'node:path';
|
|
||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
|
import path from 'node:path';
|
||||||
import { checkFileExists, checkFolderExists } from './fsChecks';
|
import { checkFileExists, checkFolderExists } from './fsChecks';
|
||||||
|
import { getLogger } from './logger';
|
||||||
import { markdownToPdf } from './markdownToPdf';
|
import { markdownToPdf } from './markdownToPdf';
|
||||||
|
|
||||||
|
const logger = getLogger("generatePdf");
|
||||||
|
|
||||||
export async function generatePdf(inputFilePath: string, outputFilePath: string) {
|
export async function generatePdf(inputFilePath: string, outputFilePath: string) {
|
||||||
|
logger.info("Checking if input file exists...");
|
||||||
if (!checkFileExists(inputFilePath)) {
|
if (!checkFileExists(inputFilePath)) {
|
||||||
throw new Error(`File ${inputFilePath} does not exist. How am I supposed to build you a resume, mate?`);
|
throw new Error(`File ${inputFilePath} does not exist. How am I supposed to build you a resume, mate?`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.info("Checking if output folder exists...");
|
||||||
if (!checkFolderExists(outputFilePath)) {
|
if (!checkFolderExists(outputFilePath)) {
|
||||||
fs.mkdirSync(outputFilePath.split('/').slice(0, -1).join("/"), { recursive: true });
|
fs.mkdirSync(outputFilePath.split('/').slice(0, -1).join("/"), { recursive: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
logger.info("Trying to generate PDF...");
|
||||||
const pdf = await markdownToPdf(inputFilePath);
|
const pdf = await markdownToPdf(inputFilePath);
|
||||||
if (pdf) {
|
if (pdf) {
|
||||||
|
logger.info("Writing PDF to file...");
|
||||||
fs.writeFileSync(path.resolve(__dirname, outputFilePath), pdf.content);
|
fs.writeFileSync(path.resolve(__dirname, outputFilePath), pdf.content);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error(`Error occurred: ${error.message}`);
|
logger.error(`Error occurred: ${error.message}`);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
14
utils/logger.ts
Normal file
14
utils/logger.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import pino from "pino";
|
||||||
|
|
||||||
|
export const getLogger = (name: string) => {
|
||||||
|
return pino({
|
||||||
|
level: process.env.NODE_ENV === "production" ? "debug" : "debug",
|
||||||
|
name,
|
||||||
|
formatters: {
|
||||||
|
level: (label) => {
|
||||||
|
return { level: label };
|
||||||
|
},
|
||||||
|
},
|
||||||
|
levelVal: 10,
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -1,11 +1,17 @@
|
|||||||
import mdToPdf from 'md-to-pdf';
|
import mdToPdf from 'md-to-pdf';
|
||||||
|
import { getLogger } from './logger';
|
||||||
|
|
||||||
|
const logger = getLogger("markdownToPdf");
|
||||||
|
|
||||||
export const markdownToPdf = async (inputFilePath: string) => {
|
export const markdownToPdf = async (inputFilePath: string) => {
|
||||||
try {
|
try {
|
||||||
|
logger.info("Converting Markdown to PDF...");
|
||||||
const pdf = await mdToPdf({ path: inputFilePath });
|
const pdf = await mdToPdf({ path: inputFilePath });
|
||||||
|
|
||||||
|
logger.info("PDF generated successfully!");
|
||||||
return pdf;
|
return pdf;
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error(`Error occurred: ${error.message}`);
|
logger.error(`Error occurred: ${error.message}`);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user