open-index/open-npm huggingface dataset:
npm package: @suin/email-data
Description: A simple email data representation for TypeScript
Author: suin
Latest version: 1.0.0

# @suin/email-data

A simple email data representation for TypeScript.

This component provides a very simple reusable interface that represents an email.

The interface was designed for the use case that treats received emails from POP3, SendGrid Inbound Parse, Gmail API and so on.

## Features

- Abstract email data type `EmailData`
- Type guard function
- Validation function
- Assertion function

### Missing Features

The following features hasn't been implemented yet:

- Some models:
  - BCC header
  - Attachments

## Installation

```bash
yarn add @suin/email-data
# or
npm install @suin/email-data
```

## Usages

### Declaring the `EmailData` value

```typescript
import { EmailData } from '@suin/email-data'

const email: EmailData = {
  from: [{ name: 'Alice', address: 'alice@example.com' }],
  to: [{ name: 'Bob', address: 'bob@example.com' }],
  cc: [],
  replyTo: [],
  subject: 'Hi',
  bodyText: 'Hello',
  bodyHtml: '<p>Hello</p>',
}
```

### Using the type guard function

```typescript
import { isEmailData } from '@suin/email-data'

const email: unknown = {
  /* ... */
}

if (isEmailData(email)) {
  console.log(email.subject)
} else {
  console.log('The value is incompatible with EmailData')
}
```

### Using the validation function

```typescript
import { parseEmailData } from '@suin/email-data'

try {
  const email = parseEmailData(JSON.parse('{}'))
  console.log('The JSON value is compatible with EmailData', email)
} catch (error) {
  console.log(error)
}
```

### Using the assertion function

```typescript
import { assertEmailData } from '@suin/email-data'

try {
  const email: unknown = JSON.parse('{}')
  assertEmailData(email)
  console.log('The JSON value is compatible with EmailData', email)
} catch (error) {
  console.log(error)
}
```

## API Reference

https://suin.github.io/email-data/
npm package: @suin/esa-api
Description: esa.io APIクライアント
Author: suin
Latest version: 4.0.1

# @suin/esa-api

esa.io API のクライアントライブラリ。

## 特徴

- すべてのエンドポイントに対応しています。
- [esa API の OpenAPI 仕様書](https://github.com/suin/esa-openapi)から生成したクライアントライブラリをベースに一部拡張を加えたライブラリです。

## インストール

```bash
yarn add @suin/esa-api
# or
npm install @suin/esa-api
```

## 使い方

基本的な用法:

```typescript
import { createClient } from "@suin/esa-api";

const teamName = "your_team_name";

const client = createClient({
  token: process.env.ESA_TOKEN, // アクセストーン
});

{
  // 記事一覧を取得する
  const {
    data: { posts },
  } = await client.getPosts({ teamName });
}

{
  // 指定した記事を取得する
  const { data: post } = await client.getPost({ teamName, postNumber: 1 });
}

{
  // 記事を新規投稿する
  const { data: createdPost } = await client.createPost({
    teamName,
    post: {
      name: "hi!",
      body_md: "# Getting Started\n",
      tags: ["api", "dev"],
      category: "dev/2015/05/10",
      wip: false,
      message: "Add Getting Started section",
    },
  });
}

{
  // 指定した記事を編集する
  const { data: updatedPost } = await client.updatePost({
    teamName,
    postNumber: 1,
    updatePostBody: {
      post: {
        wip: false,
        message: "Ship it!",
      },
    },
  });
}
```

複雑なクエリの例:

```typescript
import { createClient } from "@suin/esa-api";

const teamName = "your_team_name";

const client = createClient({
  token: process.env.ESA_TOKEN,
});

// 細かい条件を設定して記事一覧を取得する
const response = await client.getPosts({
  teamName,
  q: "wip:false",
  include: ["comments", "comments.stargazers", "stargazers"],
  sort: "updated",
  order: "desc",
  per_page: 100,
  page: 1,
});

// 結果からは様々な付随情報が得られます:
// 1. 記事一覧
const { posts } = response.data;
// 2. 利用制限
const { limit, remaining, reset } = response.ratelimit;
// 3. ページネーション
const { prev_page, next_page, page, per_page, max_per_page, total_count } =
  response.data;
```

## API リファレンス

https://suin.github.io/esa-api/
npm package: @suin/esa-exporter
Description: esa.io APIから全データをエクスポートするライブラリ
Author: suin
Latest version: 1.0.0

# @suin/esa-exporter

esa.io API から全データをエクスポートするライブラリ。

esa.io のエクスポート機能はマークダウンファイルがダウンロードできるだけで、他の情報が入ってこないためこれを開発しました。

## 特徴

- エクスポートに対応しているデータ
  - メンバー
  - 投稿
    - コメント
    - stargazers

## インストール

```bash
yarn add @suin/esa-exporter
# or
npm install @suin/esa-exporter
```

## 使い方

基本的な用法:

```typescript
import { exportAll, Entity } from "@suin/esa-exporter";

(async () => {
  const team = process.env.ESA_TEAM;
  const token = process.env.ESA_TOKEN;
  const entities: Entity[] = [];

  for await (const entity of exportAll({ team, token })) {
    entities.push(entity);
  }

  console.log(entities);
})();
```

出力例:

```javascript
[
  {
    $type: "member",
    myself: true,
    name: "Taro Tanaka",
    screen_name: "tanaka",
    icon:
      "https://img.esa.io/uploads/production/users/1/icon/thumb_m_********.png",
    role: "owner",
    posts_count: 222,
    joined_at: "2014-07-01T08:10:55+09:00",
    last_accessed_at: "2019-12-27T16:23:23+09:00",
    email: "tanaka@example.com",
  },
  {
    $type: "member",
    myself: false,
    name: "Hanako Sato",
    screen_name: "sato",
    icon:
      "https://img.esa.io/uploads/production/users/2/icon/thumb_m_********.jpg",
    role: "owner",
    posts_count: 111,
    joined_at: "2014-07-01T08:19:26+09:00",
    last_accessed_at: "2019-08-13T18:07:24+09:00",
    email: "sato@example.com",
  },
  {
    $type: "post",
    number: 1,
    name: "esa APIの使い方",
    full_name: "日報/2015/05/09/esa APIの使い方 #api #dev",
    wip: true,
    body_md: "...",
    body_html: "...",
    created_at: "2015-05-09T11:54:50+09:00",
    message: "初稿です！",
    url: "https://example.esa.io/posts/1",
    updated_at: "2015-05-09T11:54:51+09:00",
    tags: ["api", "dev"],
    category: "日報/2015/05/09",
    revision_number: 1,
    created_by: {
      myself: true,
      name: "Taro Tanaka",
      screen_name: "tanaka",
      icon:
        "https://img.esa.io/uploads/production/users/1/icon/thumb_m_********.png",
    },
    updated_by: {
      myself: true,
      name: "Taro Tanaka",
      screen_name: "tanaka",
      icon:
        "https://img.esa.io/uploads/production/users/1/icon/thumb_m_********.png",
    },
  },
];
```

`exportAll`は様々なエンティティをごちゃまぜで返してくるので、 エンティティ種別ごとに何らかの処理をする必要がある場合は、`Entity[$type]`で分岐処理を書いてください:

```typescript
import { exportAll, Member, Post } from "@suin/esa-exporter";

(async () => {
  const team = process.env.ESA_TEAM;
  const token = process.env.ESA_TOKEN;

  const members: Member[] = [];
  const posts: Post[] = [];

  for await (const entity of exportAll({ team, token })) {
    switch (entity.$type) {
      case "member":
        members.push(entity);
        break;
      case "post":
        posts.push(posts);
        break;
    }
  }
})();
```

## API リファレンス

https://suin.github.io/esa-exporter/
npm package: @suin/esa-markdown-format
Description: esa.ioのMarkdownを自動整形する関数です
Author: suin
Latest version: 1.2.0

# @suin/esa-markdown-format

esa.ioのMarkdownを自動整形する関数です。

## 特徴

- PrettierによるMarkdownの自動整形
- PrettierによるMarkdown内コードブロックの自動整形
- esa内部リンクを絶対URLから相対URLにする

どのような整形がなされるかの例は[自動整形のデモ](./demo)をご覧ください。

## インストール

```bash
yarn add @suin/esa-markdown-format
# or
npm install @suin/esa-markdown-format
```

## 使い方

`format`関数にフォーマットしたいMarkdownとチーム名を渡すと、フォーマットされたMarkdownが返ります:

```ts
import format from "@suin/esa-markdown-format";

const input = `
ヘッダ
=====

* リスト
* リスト

|カラム1|カラム2|カラム3|
|---|---|---|
|a|b|c|

~~~js
const uglyCode=function(){return 'omg'}
~~~

    const indented = "code";

[絶対URL](https://example.esa.io/posts/1)`;

const output = format(input, { team: "example" });
```

`output`の内容:

````markdown
# ヘッダ

- リスト
- リスト

| カラム1 | カラム2 | カラム3 |
| ------- | ------- | ------- |
| a       | b       | c       |

```js
const uglyCode = function () {
  return "omg";
};
```

```
const indented = "code";
```

[絶対URL](/posts/1)
````

## API リファレンス

https://suin.github.io/esa-markdown-format/
npm package: @suin/esa-toc
Description: Generates table of contents from esa.io post HTML
Author: suin
Latest version: 1.0.0

# @suin/esa-toc

このライブラリは esa.io の HTML から目次(table of contents)データを生成する関数を提供します。

## インストール

```bash
yarn add @suin/esa-toc
# or
npm install @suin/esa-toc
```

## 使い方

```typescript
import { getToc } from '@suin/esa-toc'

const html = `<h1 data-sourcepos="1:1-1:12" id="1-0-0" name="1-0-0">
              <a class="anchor" id="見出し1" name="%E8%A6%8B%E5%87%BA%E3%81%971" href="#%E8%A6%8B%E5%87%BA%E3%81%971" data-position="1-0-0"><i class="fa fa-link"></i><span class="hidden" data-text="見出し1"> &gt; 見出し1</span></a>見出し1</h1>
              <h2 data-sourcepos="2:1-2:13" id="1-1-0" name="1-1-0">
              <a class="anchor" id="見出し2" name="%E8%A6%8B%E5%87%BA%E3%81%972" href="#%E8%A6%8B%E5%87%BA%E3%81%972" data-position="1-1-0"><i class="fa fa-link"></i><span class="hidden" data-text="見出し2"> &gt; 見出し2</span></a>見出し2</h2>
              <h3 data-sourcepos="3:1-3:14" id="1-1-1" name="1-1-1">
              <a class="anchor" id="見出し3" name="%E8%A6%8B%E5%87%BA%E3%81%973" href="#%E8%A6%8B%E5%87%BA%E3%81%973" data-position="1-1-1"><i class="fa fa-link"></i><span class="hidden" data-text="見出し3"> &gt; 見出し3</span></a>見出し3</h3>
              `
const toc = getToc(html)
console.log(toc)
```

↓

```json
[
  {
    "tag": "h1",
    "depth": 1,
    "text": "見出し1",
    "href": "#%E8%A6%8B%E5%87%BA%E3%81%971"
  },
  {
    "tag": "h2",
    "depth": 2,
    "text": "見出し2",
    "href": "#%E8%A6%8B%E5%87%BA%E3%81%972"
  },
  {
    "tag": "h3",
    "depth": 3,
    "text": "見出し3",
    "href": "#%E8%A6%8B%E5%87%BA%E3%81%973"
  }
]
```

## 仕様

- esa.io の仕様に合わせて、h1, h2, h3 のみ対応しています。h4 以下は未対応。
- h1 の直下に h3 が来る場合、h3 の`depth`は`3`になります。
npm package: @suin/esa-webhook-router
Description: esa.io Webhookのペイロードをルーティングする
Author: suin
Latest version: 2.0.0

# @suin/esa-webhook-router

[esa.io の Generic Webhook]を受信し、ペイロードの`kind`ごとにルーティングするルーター。

[esa.io の generic webhook]: https://docs.esa.io/posts/37

## 特徴

- 現在、以下のペイロードに対応しています。
  - 記事作成時(kind: "post_create")
  - 記事更新時(kind: "post_update")
  - 記事アーカイブ時(kind: "post_archive")
  - 記事削除時(kind: "post_delete")
  - 記事復旧時(kind: "post_restore")
- リクエストボディ改ざん防止のための`X-Esa-Signature`に対応しています。

## 動作要件

- Node.js: 18.x 以上

## インストール

```bash
yarn add @suin/esa-webhook-router
# or
npm install @suin/esa-webhook-router
```

## 使い方

### 基本的な用法

```typescript
import { createRouter } from "@suin/esa-webhook-router";
// `createRouter`には、イベントの種類ごとに実行するハンドラー関数を渡します。
const route = createRouter({
  post_create: ({ event }) => console.log("投稿が作成されました。", event),
  post_update: ({ event }) => console.log("投稿が更新されました。", event),
  post_archive: ({ event }) =>
    console.log("投稿がアーカイブされました。", event),
  post_delete: ({ event }) => console.log("投稿が削除されました。", event),
});
// `createRouter`の戻り値は関数なので、それにHTTPリクエストを渡すと、ハンドラーが実行されます。
await route(request);
```

### AWS LambdaやNetlify Functionで使う

`createRouter`で作成した関数には、`APIGatewayProxyEvent`を渡すことができるので、AWS LambdaやNetlify Functionでもこのライブラリを用いることができるはずです。動作確認はしてません。

### `X-Esa-Signature`をあつかう

esa Webhookにはリクエストボディーの署名が[`X-Esa-Signature`](https://docs.esa.io/posts/37#X-Esa-Signature)ヘッダについています。この署名の検証を行うには次の方法のどれかで、シークレットを渡してください。

- 環境変数`ESA_WEBHOOK_SECRET`をセットする。
- `createRouter`の`secret`オプションをセットする。

どちらも設定されている場合は、`secret`オプションが優先されます。

### 使い方をもっと学ぶ

より詳しい使い方については、[usage.spec.ts](./usage.spec.ts)をご覧ください。

## 動作デモ

いろいろな環境での動作デモを用意してあります。

- [ローカル環境での動作デモ](./demo/local/main.ts): ローカル環境でHTTPサーバーを起動し、esa Webhookを受け取れるようにします。グローバルのURLはCloudflare Tunnelを使って作成しますので、実際のesaチームと結合して動作させることができます。起動するには、このリポジトリを`git clone`し、`yarn install && yarn tsx local/main.ts`を実行してください。
- [Vercel Functionsでの動作デモ](./api/webhook.ts): Vercel Functionsにデプロイして、esa Webhookを受け取れるようにします。実際のesaチームと結合して動作させることができます。ローカルで実行するには、このリポジトリを`git clone`し、`yarn install && npx vercel dev`を実行してください。

## API リファレンス

https://suin.github.io/esa-webhook-router/
npm package: @suin/event-data
Description: A simple event data representation for TypeScript
Author: suin
Latest version: 1.0.0

# @suin/event-data

A simple event data representation for TypeScript.

This component provides a very simple reusable interface that represents an event.

The interface was designed for the use case that represents event payloads of messaging system like Google Cloud Pub/Sub.

## Features

- Abstract event data type `EventData`
- Type guard function
- Validation function
- Assertion function

## Installation

```bash
yarn add @suin/event-data
# or
npm install @suin/event-data
```

## Usages

### Declaring the `EventData` value

The basic way to declare the event data is to annotate value with type `EventData`:

```typescript
import { EventData } from '@suin/event-data'

const event: EventData = {
  correlationId: '68a5e0dd-34a0-47fa-94d4-8fa2162301e3',
  data: {
    foo: 1,
    bar: 2,
  },
}
```

However, this `data` property becomes type `unknown`. If you would like to give type information to `data` property, it would be useful to use `newEventData` function, since this infers the type:

```typescript
import { newEventData } from '@suin/event-data'

const event = newEventData({
  correlationId: '68a5e0dd-34a0-47fa-94d4-8fa2162301e3',
  data: {
    foo: 1,
    bar: 2,
  },
})

const foo: number = event.data.foo
```

### Using the type guard function

```typescript
import { isEventData } from '@suin/event-data'

const event: unknown = {
  /* ... */
}

if (isEventData(event)) {
  console.log(event.correlationId)
  console.log(event.data) // NOTICE: the type is unknown
} else {
  console.log('The value is incompatible with EventData')
}
```

### Using the validation function

```typescript
import { parseEventData } from '@suin/event-data'

try {
  const event = parseEventData(JSON.parse('{}'))
  console.log('The JSON value is compatible with EventData', event)
} catch (error) {
  console.log(error)
}
```

### Using the assertion function

```typescript
import { assertEventData } from '@suin/event-data'

try {
  const event: unknown = JSON.parse('{}')
  assertEventData(event)
  console.log('The JSON value is compatible with EventData', event)
} catch (error) {
  console.log(error)
}
```

## API Reference

https://suin.github.io/event-data/
npm package: @suin/gatsby-rehype-replace-urls
Description: Gatsby rehype plugin that rewrites URLs of src/href attributes
Author: suin
Latest version: 3.0.0

# @suin/gatsby-rehype-replace-urls

Gatsby rehype plugin that rewrites URLs of src/href attributes.

## Install

```
yarn add gatsby-transformer-rehype @suin/gatsby-rehype-replace-urls
```

## How to use

```js
// In your gatsby-config.js
module.exports = {
  plugins: [
    {
      resolve: `gatsby-transformer-rehype`,
      options: {
        plugins: [
          {
            resolve: '@suin/gatsby-rehype-replace-urls',
            options: {
              replace({ url }) {
                const u = new URL(url)
                if (u.protocol === 'http:') {
                  u.protocol = 'https'
                }
                return u
              },
            },
          },
        ],
      },
    },
  ]
}
```

* To know the parameter of the `replace` function, see [API doc](https://suin.github.io/gatsby-rehype-replace-urls/modules/_index_.plugin.html#replaceparams).
* To learn more examples, see [index.test.ts](./index.test.ts).
npm package: @suin/get-connpass-applicants
Description: A simple function that gets the applicants from a given Connpass event URL.
Author: suin
Latest version: 3.0.0

# `@suin/get-connpass-applicants`

A simple function that gets the applicants from a given Connpass event URL.

## Usage

```typescript
import { getConnpassApplicants, Applicants } from '@suin/get-connpass-applicants'

(async () => {
  const url = 'https://example.connpass.com/event/123/'
  const applicants: Applicants = await getConnpassApplicants(url)
  console.log(applicants)
})()
```

For about the API of the `Applicants`, please see [Applicants.ts](./src/Applicants.ts).

## Installation

```bash
yarn add @suin/get-connpass-applicants
```
npm package: @suin/get-connpass-applicants-cli
Description: A simple CLI command that gets the applicants from a given Connpass event URL.
Author: suin
Latest version: 1.0.0

# `@suin/get-connpass-applicants-cli`

A simple CLI command that gets the applicants from a given Connpass event URL.

## Usage

```
connpass-applicants https://connpass.com/event/123/
```

### Details

```bash
A simple CLI command that gets the applicants from a given Connpass event URL.

USAGE
  $ connpass-applicants URL

ARGUMENTS
  URL  Connpass event URL (eg. https://connpass.com/event/144296/)

OPTIONS
  -h, --help         show CLI help
  -v, --version      show CLI version
  --format=json|csv  [default: json] output format
  --pretty           enable pretty print (works only json format)

EXAMPLES
  Basic usage:
  $ connpass-applicants https://connpass.com/event/144296/

  Output as CSV format:
  $ connpass-applicants https://connpass.com/event/144296/ --format=json --pretty

  Print only accepted applicants as CSV (working with q command):
  $ connpass-applicants https://connpass.com/event/144296/ --format=csv | q \
     --skip-header \
     --delimiter=',' \
     'SELECT displayName, participationType FROM - WHERE status = "accepted"'

  NOTE: the value of the status is one of "accepted", "waiting" and "canceled"

  Print attendants like Markdown table (working with q command);
  $ connpass-applicants https://connpass.com/event/144296/ --format=csv | q \
     --skip-header \
     --delimiter=',' \
     --output-header \
     --output-delimiter=' | ' \
     --beautify \
     'SELECT nickName, displayName, url FROM - WHERE status = "accepted" AND participationType = "現地参加"'

  Print only accepted applicants as JSON (working with jq command):
  $ connpass-applicants https://connpass.com/event/144296/ | jq \
     '[ .[] | select(.status == "accepted") | { name: .displayName, type: .participationType } ]'

  NOTE: the value of the status is one of "accepted", "waiting" and "canceled"
```

## Installation

```bash
yarn global add @suin/get-connpass-applicants-cli
```
npm package: @suin/google-cloud-typed-pubsub-function
Description: Strongly typed Google Cloud Function interface of the Pub/Sub handler for TypeScript
Author: suin
Latest version: 1.0.0

# @suin/google-cloud-typed-pubsub-function

Strongly typed Google Cloud Function interface of the Pub/Sub handler for TypeScript.

## Installation

```bash
yarn add @suin/google-cloud-typed-pubsub-function
# or
npm install @suin/google-cloud-typed-pubsub-function
```

## Usage

```typescript
import { PubSubFunction } from '@suin/google-cloud-typed-pubsub-function'

export const receiveEvent: PubSubFunction = (event, context) => {
  event.data // string
  event.attributes // null or object
  context.eventType // string
  context.eventId // string
  context.timestamp // string
}
```

## API Reference

https://suin.github.io/google-cloud-typed-pubsub-function/
npm package: @suin/japannetbank-email-parser
Description: ジャパンネット銀行の通知メールをパースしてオブジェクトを返す関数
Author: suin
Latest version: 1.0.0

# @suin/japannetbank-email-parser

ジャパンネット銀行からの通知メールをパースしてオブジェクトにして返す関数。

## 通知対応状況

以下の通知をパースすることができます。

**自動振込サービス**

- ✅ 自動振込サービスのご確認 - [automaticTransferRegistrationCreated](./automaticTransferRegistrationCreated.ts)
- ✅ 自動振込サービス登録削除のご連絡 - [automaticTransferRegistrationDeleted](./automaticTransferRegistrationDeleted.ts)
- ✅ 自動振込サービス登録内容変更のご連絡 - [automaticTransferRegistrationUpdated](./automaticTransferRegistrationUpdated.ts)

**WEB 総振**

- ✅ ＷＥＢ総振の振込実施のお知らせ - [bulkTransferCompleted](./bulkTransferCompleted.ts)
- ✅ ＷＥＢ総振手数料引落のお知らせ - [bulkTransferUpcoming](./bulkTransferUpcoming.ts)
- ✅ ＷＥＢ総振実施の事前連絡 - [bulkTransferUpcoming](./bulkTransferUpcoming.ts)

**ペイジー**

- ✅ ペイジー払い込みのご確認 - [payeasyPaid](./payeasyPaid.ts)

**定期預金**

- ✅ 定期預金自動継続のご案内 - [timeDepositAutomaticallyRenewed](./timeDepositAutomaticallyRenewed.ts)
- ✅ 定期預金新約のご案内 - [timeDepositCreated](./timeDepositCreated.ts)
- ✅ 定期預金の満期を迎えたお客さまへ - [timeDepositMatured](./timeDepositMatured.ts)
- ✅ 定期預金の満期を迎えるお客さまへ - [timeDepositWillMature](./timeDepositWillMature.ts)

**振込**

- ✅ 振込入金のご連絡 - [transferDeposited](./transferDeposited.ts)
- ✅ 振込先口座の登録のご確認 - [transferDestinationRegistered](./transferDestinationRegistered.ts)
- ✅ 振込限度額変更のご確認 - [transferWithdrawalLimitChanged](./transferWithdrawalLimitChanged.ts)
- ✅ 振込予約のご確認 - [transferWithdrawalScheduled](./transferWithdrawalScheduled.ts)
- ✅ 振り込みのご確認 - [transferWithdrawn](./transferWithdrawn.ts)

**VISA デビット**

- ✅ 【重要】Ｖｉｓａデビット利用停止のご連絡 - [visaFrozen](./visaFrozen.ts)
- ✅ 【ＪＮＢ／Ｖｉｓａデビット】利用限度額変更のお知らせ - [visaLimitChanged](./visaLimitChanged.ts)
- ✅ 【Ｖｉｓａデビット】ご利用代金ご返金のお知らせ - [visaRefunded](./visaRefunded.ts)
- ✅ 【Ｖｉｓａデビット】ご利用代金お引き落としのお知らせ - [visaWithdrawn](./visaWithdrawn.ts)

## インストール方法

```bash
yarn add @suin/japannetbank-email-parser
# or
npm install @suin/japannetbank-email-parser
```

## 用法

基本的な用法としては、`parseJapannetbankNotification`関数にメールの題名と本文を渡します。この関数は題名と本文をパースします。パースが成功した場合は[JapannetbankNotification](./index.ts)を返します。未対応な通知の場合は`undefined`を返します。

```typescript
import { parseJapannetbankNotification } from '@suin/japannetbank-email-parser'

const notification = parseJapannetbankNotification({
  subject: '【Ｖｉｓａデビット】ご利用代金お引き落としのお知らせ',
  text: `
いつもジャパンネット銀行をご利用いただきありがとうございます。
JNB Visaデビットのご利用代金を普通預金口座よりお引き落としいたしました。

お引落日時：2020/07/27 02:47:20
お引落金額：2,205円
加盟店名：ＧＩＴＨＵＢ
取引明細番号：1A209002

▽JNB Visaデビットは還元率25％のマイナポイント事業の対象です！`,
})

console.log(notification)
//=> {
//     type: 'visaWithdrawn',
//     withdrawnOn: '2020-07-27T02:47:20+09:00',
//     useOfDate: undefined,
//     amount: 2205,
//     shop: 'ＧＩＴＨＵＢ',
//     number: '1A209002'
//   }
```

通知種別ごとに分岐処理する場合は、`JapannetbankNotification`の`type`プロパティをヒントにしてください。

## API リファレンス

https://suin.github.io/japannetbank-email-parser/
npm package: @suin/logger
Description: A simple logger interface for backend apps.
Author: suin
Latest version: 2.0.1

# @suin/logger

A simple logger for backend apps.

## Features

> TODO

## Installation

```bash
yarn add @suin/logger
# or
npm install @suin/logger
```

## Usage

Basic usage:

```typescript
import {Logger, muteLogger, console} from "@suin/logger";

function doSomething(logger: Logger = muteLogger) {
    logger.log("operation started");
}

doSomething(console);
```

## API Reference

https://suin.github.io/logger/
npm package: @suin/mdast-character-count
Description: A utility to count characters in Markdown
Author: suin
Latest version: 1.0.0

# @suin/mdast-character-count

[mdast] utility to count characters.

## Installation

```bash
yarn add @suin/mdast-character-count
# or
npm install @suin/mdast-character-count
```

## Usage

```ts
import { countCharacter } from "@suin/mdast-character-count";

const text = markdown`
# 12345

1234567890

- 12345
- 12345

~~~
12345
~~~
`;
const tree = mdastUtilFromMarkdown(text);
const { textCharacters, codeCharacters } = countCharacter(tree);

console.log(textCharacters); //=> 25
console.log(codeCharacters); //=> 5
```

More examples, see [example.test.ts](./example.test.ts).

## API Reference

https://suin.github.io/mdast-character-count/
npm package: @suin/next-auth-esa-provider
Description: esa.io OAuth provider for Next Auth.
Author: suin
Latest version: 1.0.0

# @suin/next-auth-esa-provider

esa.io OAuth provider for [Next Auth].

[Next Auth]向けの esa.io の OAuth プロバイダー。

[next auth]: https://next-auth.js.org/

## Features

- Next Auth のビルトインプロバイダーと同じような書き方で、esa.io の OAuth を組み込むことができます。

## Installation

```bash
yarn add @suin/next-auth-esa-provider
# or
npm install @suin/next-auth-esa-provider
```

## Usage

Basic usage:

```typescript
import "@suin/next-auth-esa-provider"; // import this!
import NextAuth from "next-auth";
import Providers from "next-auth/providers";

export default NextAuth({
  providers: [
    Providers.Esa({
      clientId: process.env.ESA_ID ?? "",
      clientSecret: process.env.ESA_SECRET ?? "",
      // 書き込み権限も付与しつつ認可する場合は次のコメントアウトを外してください
      // scope: "read write",
    }),
  ],
  secret: process.env.SECRET,
  session: {
    jwt: true,
  },
  callbacks: {
    // クライアントサイドでesaのアクセストークンを参照する必要がない場合は、次のコールバックをコメントアウトしてください。
    async jwt(token, _user, account, _profile, _isNewUser) {
      if (account?.accessToken) {
        return { ...token, accessToken: account.accessToken };
      }
      return token;
    },
  },
});
```

## API Reference

https://suin.github.io/next-auth-esa-provider/
npm package: @suin/non-exhaustive-error
Description: An error class to detect non-exhaustive if/switch statements in TypeScript.
Author: suin
Latest version: 1.0.0

# @suin/non-exhaustive-error

An error class to detect non-exhaustive if/switch statements in TypeScript.

## Installation

```bash
yarn add @suin/non-exhaustive-error
# or
npm install @suin/non-exhaustive-error
```

## Usage

### Basic Usage

Use `NonExhaustiveError` in default case of `switch` statement.

```typescript
import { NonExhaustiveError } from "@suin/non-exhaustive-error";

type Status = "good" | "normal" | "bad";

function statusToNumber(status: Status): number {
  switch (status) {
    case "good":
      return 1;
    case "normal":
      return 0;
    default:
      // this switch statement is non-exhaustive as here is no case statement for "bad".
      throw new NonExhaustiveError(status); // You will get a compile error here by TypeScript compiler check.
  }
}
```

## API Reference

https://suin.github.io/non-exhaustive-error/
npm package: @suin/print-http
Description: Pretty-print HTTP requests and responses with syntax highlighting support
Author: suin
Latest version: 0.1.0

# @suin/print-http

[![npm version](https://img.shields.io/npm/v/@suin/print-http.svg)](https://www.npmjs.com/package/@suin/print-http)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Node.js Version](https://img.shields.io/node/v/@suin/print-http.svg)](https://nodejs.org/)

Pretty-print HTTP requests and responses with syntax highlighting support.

## Features

- 🎨 Syntax highlighting for HTTP headers and JSON bodies
- 🔍 Automatic JSON body formatting
- 📝 Support for both Request and Response objects
- 🎯 Type-safe with TypeScript
- 🪶 Zero dependencies (except for optional syntax highlighting)

## Installation

```bash
npm install @suin/print-http
```

```bash
yarn add @suin/print-http
```

```bash
pnpm add @suin/print-http
```

```bash
bun add @suin/print-http
```

## Usage

### Print HTTP Request

```typescript
import { printHttp } from '@suin/print-http';

const request = new Request('https://api.example.com/users', {
  method: 'POST',
  headers: {
    'content-type': 'application/json',
    'authorization': 'Bearer token123'
  },
  body: JSON.stringify({
    name: 'John Doe',
    email: 'john@example.com'
  })
});

const output = await printHttp(request);
console.log(output);
```

Output:
```http
POST /users HTTP/1.1
authorization: Bearer token123
content-type: application/json
host: api.example.com

{
  "name": "John Doe",
  "email": "john@example.com"
}
```

### Print HTTP Response

```typescript
import { printHttp } from '@suin/print-http';

const response = new Response(
  JSON.stringify({ message: 'Success' }),
  {
    status: 200,
    headers: {
      'content-type': 'application/json'
    }
  }
);

const output = await printHttp(response);
console.log(output);
```

Output:
```http
HTTP/1.1 200 OK
content-type: application/json

{
  "message": "Success"
}
```

## API

### `printHttp(object, options?): Promise<string>`

Formats an HTTP request or response object into a string representation.

#### Parameters

- `object`: `Request | Response` - The HTTP request or response object to format
- `options?`: `Object` (optional)
  - `color?`: `boolean` - Enable/disable syntax highlighting (default: `true`)
  - `highlighter?`: `Highlighter` - Custom syntax highlighter implementation

#### Returns

- `Promise<string>` - The formatted HTTP message

### Highlighter Interface

```typescript
interface Highlighter {
  highlight(lang: string, value: string): Promise<string>;
}
```

## Requirements

- Node.js >= 22.0.0

## License

MIT License - see the [LICENSE](LICENSE) file for details.
npm package: @suin/refractor-flatten
Description: A utility to transform Refractor ASTs to flat arrays.
Author: suin
Latest version: 1.0.0

# @suin/refractor-flatten

A utility to transform [Refractor](https://github.com/wooorm/refractor) ASTs to flat arrays.

## Installation

```bash
yarn add @suin/refractor-flatten
# or
npm install @suin/refractor-flatten
```

## Usage

### Basic Usage

```typescript
import refractor from "refractor";
import flatten from "@suin/refractor-flatten";

const tree = refractor.highlight("`${value}`", "js");
const flat = flatten(tree);
```

The structure of `tree` is:

```
root[1]
└─0 element<span>[3]
    │ properties: {"className":["token","template-string"]}
    ├─0 element<span>[1]
    │   │ properties: {"className":["token","template-punctuation","string"]}
    │   └─0 text "`"
    ├─1 element<span>[3]
    │   │ properties: {"className":["token","interpolation"]}
    │   ├─0 element<span>[1]
    │   │   │ properties: {"className":["token","interpolation-punctuation","punctuation"]}
    │   │   └─0 text "${"
    │   ├─1 text "value"
    │   └─2 element<span>[1]
    │       │ properties: {"className":["token","interpolation-punctuation","punctuation"]}
    │       └─0 text "}"
    └─2 element<span>[1]
        │ properties: {"className":["token","template-punctuation","string"]}
        └─0 text "`"
```

The structure of the `flat` above becomes:

```
root[5]
├─0 element<span>[1]
│   │ properties: {"className":["token","template-string","template-punctuation","string"]}
│   └─0 text "`"
├─1 element<span>[1]
│   │ properties: {"className":["token","template-string","interpolation","interpolation-punctuation","punctuation"]}
│   └─0 text "${"
├─2 element<span>[1]
│   │ properties: {"className":["token","template-string","interpolation"]}
│   └─0 text "value"
├─3 element<span>[1]
│   │ properties: {"className":["token","template-string","interpolation","interpolation-punctuation","punctuation"]}
│   └─0 text "}"
└─4 element<span>[1]
    │ properties: {"className":["token","template-string","template-punctuation","string"]}
    └─0 text "`"
```

## API Reference

https://suin.github.io/refractor-flatten/
npm package: @suin/runspace
Description: Isolated execution context for Node.js.
Author: suin
Latest version: 2.3.0

# @suin/runspace

Isolated execution context for Node.js.

## Installation

```shell script
# via NPM
npm install --save @suin/runspace
# via Yarn
yarn add @suin/runspace
```

## Usage

Basic usage:

```javascript
// main.js
const { ThreadSpace, ChildProcessSpace } = require("@suin/runspace");

(async () => {
  const space = new ThreadSpace({ filename: "./target.js" }) // Or new ChildProcessSpace({ filename: "./target.js" })
    .on("message", (message) => console.log(message))
    .on("error", (error) => console.error(error))
    .on("rejection", (reason) => console.error(reason));

  await space.waitStart();
  space.send("Hello");
  await space.waitStop();
})();

// target.js
process.on("message", (message) => {
  process.send(message + " World");
  process.exit();
});

// Output:
// "Hello World"
```

Waits a message from the program inside the space:

```javascript
// target.js
const http = require("http");

const server = http.createServer((req, res) => {
  res.write("OK");
  res.end();
});
server.listen(8000, () => {
  process.send("HTTP_SERVER_READY");
});

// main.js
const { ThreadSpace } = require("@suin/runspace");
const fetch = require("node-fetch");

(async () => {
  const space = new ThreadSpace({ filename: "./target.js" });
  await space.waitStart();
  await space.waitMessage((message) => message === "HTTP_SERVER_READY");
  const res = await fetch("http://localhost:8000");
  const text = await res.text();
  await space.stop();
  console.log(text); // Output: "OK"
})();
```
npm package: @suin/typed-event-emitter
Description: Strongly typed EventEmitter interface for TypeScript
Author: suin
Latest version: 1.0.0

# @suin/typed-event-emitter

Strongly typed EventEmitter interface for TypeScript.

## Installation

```bash
yarn add @suin/typed-event-emitter
# or
npm install @suin/typed-event-emitter
```

## Usage

```typescript
import { EventEmitter } from 'events'
import { TypedEventEmitter } from '@suin/typed-event-emitter'

const event = new EventEmitter() as TypedEventEmitter<{
  success: (value: string) => void
  failure: (error: Error) => void
}>
event.on('success', value => {
  console.log('success! %o', value)
})
event.on('failure', error => {
  console.log('failure! %o', error)
})
event.emit('success', `It's OK`)
event.emit('failure', new Error('Something wrong...'))

// Followings occurs compile errors!
event.on('foobar', value => {})
//       ^^^^^^^^
// 🚫Argument type "foobar" is not assignable to parameter type keyof {success: (value: string) => void, failure: (error: Error) => void}
event.on('success', (value: number) => {})
//                  ^^^^^^^^^^^^^^^^^^^^^
// 🚫Argument type (value: number) => void is not assignable to parameter type {success: (value: string) => void, failure: (error: Error) => void}["success"]
```

## API Reference

https://suin.github.io/typed-event-emitter/
npm package: @suin/typed-regexp
Description: A TypeScript utility to write type-safe regular expressions using named capture groups
Author: suin
Latest version: 1.0.0

# @suin/typed-regexp

A TypeScript utility to write type-safe regular expressions using named capture groups.

## Installation

```bash
yarn add @suin/typed-regexp
# or
npm install @suin/typed-regexp
```

## Usage

```ts
import typedRegExp from "@suin/typed-regexp";

const urlPattern = typedRegExp(
  "^(?:(?<protocol>https?:)(?:\\/\\/\\/?)(?:(?<auth>(?<user>[\\w]*)(?::(?<pass>[\\w]*))?)@)?(?<hostname>[\\d\\w\\.-]+)(?::(?<port>\\d+))?)?(?<pathname>[\\/\\\\\\w\\.()-]*)?(?:(?<search>[?](?<query>[^#]*))?(?<hash>#.*)?)*$",
  "i"
);
const matches = urlPattern.exec(
  "https://user:pass@sub.example.com:8080/p/a/t/h?query=string#hash"
);
if (matches) {
  const { user, pass, hostname, port } = matches.groups;
  console.log({ user, pass, hostname, port });
  //=> {
  //  "hostname": "sub.example.com",
  //  "pass": "pass",
  //  "port": "8080",
  //  "user": "user",
  // }
}
```

## API Reference

https://suin.github.io/typed-regexp/
npm package: @suinegmai/js-events
Description: Simple Javascript event emitter
Author: lkmtri
Latest version: 1.0.5

## Tiny pubsub library in JS
### Install
```
npm install @suinegmai/js-events

or

yarn add @suinegmai/js-events
```
### Usage in JavaScript

```typescript
import EventEmitter from '@suinegmai/js-events'

const ev = EventEmitter()

const onMount = (...args) => console.log('mount: ', ...args)
const onUpdate = (...args) => console.log('update: ', ...args)
const onUnmount = (...args) => console.log('unmount: ', ...args)

//Subscribe to 'mount' event, but only trigger the callback once.
ev.once('mount', onMount)

//Subscribe to 'update' event, the callback is trigger for every 'update' event
ev.on('update', onUpdate)

//Subscribe to 'unmount' event, but only trigger the callback once.
ev.once('unmount', onUnmount)


ev.emit('mount', 'First mount')
ev.emit('mount', 'Second mount')
ev.emit('update', { state: 1 })
ev.emit('update', { state: 2 })
ev.emit('unmount', 0)

//Unsubscribe onUpdate
ev.off('update', onUpdate)

//Console output
mount: First mount
update: { state: 1 }
update: { state: 2 }
unmount: 0
```

### Usage in TypeScript
```typescript
import EventEmitter from '@suinegmai/js-events'

type Event = {
  mount: string
  update: {
    state: number
  }
  unmount: number
}

const ev = EventEmitter<Event>()

const onMount = (...args) => console.log('mount: ', ...args)
const onUpdate = (...args) => console.log('update: ', ...args)
const onUnmount = (...args) => console.log('unmount: ', ...args)

//Subscribe to 'mount' event, but only trigger the callback once.
ev.once('mount', onMount)

//Subscribe to 'update' event, the callback is trigger for every 'update' event
ev.on('update', onUpdate)

//Subscribe to 'unmount' event, but only trigger the callback once.
ev.once('unmount', onUnmount)


ev.emit('mount', 'First mount')
ev.emit('mount', 'Second mount')
ev.emit('update', { state: 1 })
ev.emit('update', { state: 2 })
ev.emit('unmount', 0)

//Unsubscribe onUpdate
ev.off('update', onUpdate)

//Console output
mount: First mount
update: { state: 1 }
update: { state: 2 }
unmount: 0
```
npm package: @suinegmai/react-teleport
Description: Easy react portal
Author: lkmtri
Latest version: 1.0.5

# react-teleport

Simple React portal

[![npm version](https://badge.fury.io/js/%40suinegmai%2Freact-teleport.svg)](https://badge.fury.io/js/%40suinegmai%2Freact-teleport)

## Installation

```
npm i @suinegmai/react-teleport
```

or

```
yarn @suinegmai/react-teleport
```

## Usage

```javascript
import { createPortal } from '@suinegmai/react-teleport'

const Portal = createPortal()

function App() {
  return (
    <div>
      <Portal.Target />
      <div>
        Somewhere
        <div>
          deep
          <div>
            in
            <div>
              the
              <div>
                tree
                <Portal.Source>
                  <p>This will be rendered to Portal.Target node</p>
                </Portal.Source>
              </div>
              <Portal.Source>
                <p>Multiple sources can be rendered to a single target</p>
              </Portal.Source>
            </div>
          </div>
        </div>
      </div>
    </div>
  )
}
```