Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
docs/
.github/
.claude/
.wrangler/
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ jobs:
- lint
- test
runs-on: ubuntu-22.04
name: Release
name: release-container
permissions:
packages: write
contents: read
Expand Down
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -183,4 +183,7 @@ ynab_connect

# docs
docs/.vitepress/dist
docs/.vitepress/cache
docs/.vitepress/cache

# Claude Code
.claude
68 changes: 68 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Claude Instructions

## Tech Stack

This project uses Bun.

## Useful commands

This projects uses Biome for linting and formatting. You can run it with:

```bash
bun lint
```

and fix with:

```bash
bun lint:fix
```

Prefer fixing with Biome over manually fixing linting errors.

Run type checks with

```bash
bun types
```

## Good Practice

When installing new packages use the `-E` flag to pin the version of the package in `bun.lockb`.

Before implementing a new feature, see if there is an existing implementation in the codebase that you can reuse or extend.

## Testing

Always write unit tests for new features. This projects uses Bun testing. It's very similar to Jest and Vitest. You must import it, describe, etc. from 'bun:test'.

Avoid mocking dependencies, except in cases where the dependency is external (e.g., network requests, database calls).

In cases where you need to mock something external, see if you can mock the network request or database call directly instead of mocking the entire dependency.

## Working with the engineer

Before implementing a new feature, discuss it with the engineer to ensure alignment on the approach and design.

Come up with a plan.

## Coding style

Avoid being too clever. Write code that is easy to read and understand.

E.g. avoid double ternaries, complex one-liners, etc.

Prefer typing out things instead of using advanced TypeScript features that make the code harder to read.

# Writing documentation
This project uses Vitepress for documentation.

When writing documentation, follow the existing style and structure in the docs folder.

Guides go in the `docs/guide` folder.

Connectors go in the `docs/connectors` folder.

Write in a concise and clear manner. Do not use emojis. Do not over explain, but when needed create a guide to explain a concept.

When adding a new guide or connector, update the sidebar in `docs/.vitepress/config.ts` to include the new documentation.
2 changes: 1 addition & 1 deletion biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
},
"files": {
"ignoreUnknown": false,
"includes": ["src"]
"includes": ["src/**/*.ts"]
},
"formatter": {
"enabled": true,
Expand Down
Binary file modified bun.lockb
Binary file not shown.
51 changes: 47 additions & 4 deletions docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,47 @@
import fs from "node:fs";
import path from "node:path";
import { defineConfig } from "vitepress";

// Helper function to extract title from markdown frontmatter
function extractTitle(filePath: string): string {
const content = fs.readFileSync(filePath, "utf-8");
const frontmatterMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);

if (frontmatterMatch) {
const titleMatch = frontmatterMatch[1].match(/title:\s*(.+?)(?:\r?\n|$)/);
if (titleMatch) {
return titleMatch[1].trim().replace(/['"]/g, "");
}
}

// Fallback to filename
return path
.basename(filePath, ".md")
.split("-")
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
.join(" ");
}

// Generate sidebar items from directory
function generateSidebarItems(dir: string, urlPrefix: string) {
const fullPath = path.join(__dirname, "..", dir);

if (!fs.existsSync(fullPath)) {
return [];
}

return fs
.readdirSync(fullPath)
.filter((file) => file.endsWith(".md"))
.map((file) => {
const filePath = path.join(fullPath, file);
const title = extractTitle(filePath);
const link = `/${urlPrefix}/${path.basename(file, ".md")}`;
return { text: title, link };
})
.sort((a, b) => a.text.localeCompare(b.text));
}

// https://vitepress.dev/reference/site-config
export default defineConfig({
title: "ynab-connect",
Expand All @@ -19,16 +61,17 @@ export default defineConfig({
{ text: "Configuration", link: "/configuration" },
],
},
{
text: "Guides",
items: generateSidebarItems("guide", "guide"),
},
{
text: "Features",
items: [{ text: "Browser", link: "/browser" }],
},
{
text: "Connectors",
items: [
{ text: "Trading 212", link: "/connectors/trading-212" },
{ text: "UK Student Loan", link: "/connectors/uk-student-loan" },
],
items: generateSidebarItems("connectors", "connectors"),
},
],

Expand Down
36 changes: 36 additions & 0 deletions docs/connectors/standard-life-pension.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
title: Standard Life Pension
---
# Standard Life Pension

Sync your Standard Life UK pension balance.

This connector uses a [headless browser](/browser) to log in to your account and retrieve your pension balance.

This connector is only available for UK accounts.

## Two-factor authentication

Standard Life requires two-factor authentication via SMS. You will need to set up SMS forwarding to automatically provide the code.

See the [SMS forwarding guide](/guide/sms-forwarding) for instructions on how to set this up.

## Finding your policy number

To find your policy number:

1. Log in to [Standard Life online](https://online.standardlife.com/secure/customer-authentication-client/customer/login)
2. Navigate to your pension dashboard
3. Your policy number will be displayed on your pension plan details

## Sample configuration

```yaml
- name: "Standard Life Pension"
type: "standard_life_pension"
interval: "0 0 * * *"
ynabAccountId: "YOUR_YNAB_ACCOUNT_ID"
username: "YOUR_STANDARD_LIFE_USERNAME"
password: "YOUR_STANDARD_LIFE_PASSWORD"
policyNumber: "YOUR_POLICY_NUMBER"
```
2 changes: 1 addition & 1 deletion docs/connectors/uk-student-loan.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: Bruh
title: UK Student Loan
---
# UK Student Loan
Sync your UK Student Loan balance from the Student Loans Company website.
Expand Down
26 changes: 26 additions & 0 deletions docs/guide/sms-forwarding.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
title: SMS Forwarding for 2FA
---
# SMS Forwarding for 2FA

Some connectors require two-factor authentication via SMS. To enable automatic authentication, you need to set up SMS forwarding.

## Overview

The SMS forwarding setup allows ynab-connect to receive 2FA codes sent to your phone automatically. When a connector requires a 2FA code, it will wait for the code to be forwarded to the application.

## Requirements

- A smartphone (iOS or Android)
- Access to SMS messages
- A method to forward SMS to the ynab-connect server

## Setup Instructions

Documentation for setting up SMS forwarding will be added here.

## Supported Connectors

The following connectors support 2FA via SMS:

- [Standard Life Pension](/connectors/standard-life-pension)
3 changes: 0 additions & 3 deletions lefthook.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,4 @@ pre-commit:
parallel: true
jobs:
- run: bun run lint
glob: "*.ts"

- run: bun test
glob: "*.ts"
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"scripts": {
"lint": "biome check",
"lint:fix": "biome check --write",
"types": "tsc --noEmit",
"build:binary": "bun build src/index.ts --compile --minify --sourcemaps --outfile ynab-connect",
"docs:dev": "vitepress dev docs",
"docs:build": "vitepress build docs",
Expand All @@ -25,7 +26,7 @@
"dependencies": {
"node-cron": "4.2.1",
"pino": "10.0.0",
"puppeteer-core": "24.24.0",
"puppeteer": "24.25.0",
"retry": "0.13.1",
"yaml": "2.8.1",
"ynab": "2.10.0",
Expand Down
Loading