@bagooon/chatease-node-client 0.1.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/README.md +273 -0
- package/dist/client.d.ts +22 -0
- package/dist/client.js +83 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -0
- package/dist/types.d.ts +54 -0
- package/dist/types.js +2 -0
- package/dist/validators.d.ts +27 -0
- package/dist/validators.js +63 -0
- package/package.json +46 -0
package/README.md
ADDED
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
# @bagooon/chatease-node-client
|
|
2
|
+
|
|
3
|
+
Node.js 向けの **ChatEase チャットボード API クライアント** です。
|
|
4
|
+
サーバーサイド(Node.js)専用で、ブラウザからの利用は想定していません。
|
|
5
|
+
|
|
6
|
+
> ⚠️ This package is **Node.js-only**.
|
|
7
|
+
> Do **NOT** use it in browser environments. Your API token will be exposed.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- ChatEase の「チャットボード生成 API」を安全にラップ
|
|
14
|
+
- 3パターンのメソッドを提供
|
|
15
|
+
- チャットボード生成のみ
|
|
16
|
+
- チャットボード + 初期ステータス
|
|
17
|
+
- チャットボード + 初期ステータス + 初期投稿
|
|
18
|
+
- TypeScript フルサポート(型定義同梱)
|
|
19
|
+
- 実行時バリデーション
|
|
20
|
+
- `timeLimit` の日付妥当性(`YYYY-MM-DD` & 実在日付)
|
|
21
|
+
- `guest.email` の簡易フォーマットチェック
|
|
22
|
+
- `boardUniqueKey` の妥当性チェック
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Requirements
|
|
27
|
+
|
|
28
|
+
- Node.js **18+** (グローバル `fetch` が必要)
|
|
29
|
+
- ChatEase のワークスペーススラッグ & API トークン
|
|
30
|
+
- サーバーサイド(Node.js)環境のみ
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Installation
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm install @bagooon/chatease-node-client
|
|
38
|
+
# or
|
|
39
|
+
yarn add @bagooon/chatease-node-client
|
|
40
|
+
# or
|
|
41
|
+
pnpm add @bagooon/chatease-node-client
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Quick Start
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
import { ChatEaseClient } from '@hashimoto-giken/chatease-node-client'
|
|
50
|
+
|
|
51
|
+
const chatease = new ChatEaseClient({
|
|
52
|
+
apiToken: process.env.CHATEASE_API_TOKEN!,
|
|
53
|
+
workspaceSlug: 'your-workspace-slug',
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
// 1) チャットボードのみ生成
|
|
57
|
+
const res1 = await chatease.createBoard({
|
|
58
|
+
title: 'お問い合わせ #1001',
|
|
59
|
+
guest: {
|
|
60
|
+
name: '田中太郎',
|
|
61
|
+
email: 'taro@example.com',
|
|
62
|
+
},
|
|
63
|
+
boardUniqueKey: '20260225-1001',
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
console.log(res1.guestURL)
|
|
67
|
+
|
|
68
|
+
// 2) 初期ステータス付きで生成
|
|
69
|
+
const res2 = await chatease.createBoardWithStatus({
|
|
70
|
+
title: '見積依頼 #1002',
|
|
71
|
+
guest: {
|
|
72
|
+
name: 'Suzuki Hanako',
|
|
73
|
+
email: 'hanako@example.com',
|
|
74
|
+
},
|
|
75
|
+
boardUniqueKey: '20260225-1002',
|
|
76
|
+
initialStatus: {
|
|
77
|
+
statusKey: 'scheduled_for_response',
|
|
78
|
+
timeLimit: '2026-02-28', // YYYY-MM-DD
|
|
79
|
+
},
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
// 3) 初期ステータス + 初期投稿付きで生成
|
|
83
|
+
const res3 = await chatease.createBoardWithStatusAndMessage({
|
|
84
|
+
title: 'デザイン相談 #1003',
|
|
85
|
+
guest: {
|
|
86
|
+
name: 'John Smith',
|
|
87
|
+
email: 'john@example.com',
|
|
88
|
+
},
|
|
89
|
+
boardUniqueKey: '20260225-1003',
|
|
90
|
+
initialStatus: {
|
|
91
|
+
statusKey: 'scheduled_for_proof',
|
|
92
|
+
timeLimit: '2026-03-05',
|
|
93
|
+
},
|
|
94
|
+
initialGuestComment: {
|
|
95
|
+
content: 'ロゴデザインについて相談したいです。現在の案を添付しました。',
|
|
96
|
+
},
|
|
97
|
+
})
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## API
|
|
103
|
+
|
|
104
|
+
### `new ChatEaseClient(options)`
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
interface ChatEaseClientOptions {
|
|
108
|
+
apiToken: string
|
|
109
|
+
workspaceSlug: string
|
|
110
|
+
baseUrl?: string // default: 'https://chatease.jp'
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
- `apiToken` – ChatEase の API トークン
|
|
115
|
+
- `workspaceSlug` – ワークスペースの slug
|
|
116
|
+
- `baseUrl` – ステージングなどを使う場合に差し替え。通常は指定不要。
|
|
117
|
+
|
|
118
|
+
ブラウザ環境(window が存在する)で呼び出すと、即座にエラーを投げます。
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
### `createBoard(params)`
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
interface GuestInfo {
|
|
126
|
+
name: string
|
|
127
|
+
email: string
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
interface CreateBoardBaseParams {
|
|
131
|
+
title: string
|
|
132
|
+
guest: GuestInfo
|
|
133
|
+
boardUniqueKey: string
|
|
134
|
+
inReplyTo?: string
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
createBoard(params: CreateBoardBaseParams): Promise<CreateBoardResponse>
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
最低限の情報でチャットボードを生成します。
|
|
141
|
+
|
|
142
|
+
- `boardUniqueKey` は同じ値で再度呼び出すと、既存ボードが返ってくる仕様です
|
|
143
|
+
- `guest.email` は簡易フォーマットチェックが行われます
|
|
144
|
+
- `boardUniqueKey` は空文字や空白を含む値は拒否されます
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
### `createBoardWithStatus(params)`
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
type ChatEaseStatusKey =
|
|
152
|
+
| 'scheduled_for_proof'
|
|
153
|
+
| 'scheduled_for_response'
|
|
154
|
+
| 'scheduled_for_completion'
|
|
155
|
+
| 'waiting_for_reply'
|
|
156
|
+
|
|
157
|
+
type InitialStatus =
|
|
158
|
+
| {
|
|
159
|
+
statusKey:
|
|
160
|
+
| 'scheduled_for_proof'
|
|
161
|
+
| 'scheduled_for_response'
|
|
162
|
+
| 'scheduled_for_completion'
|
|
163
|
+
timeLimit: string // YYYY-MM-DD
|
|
164
|
+
}
|
|
165
|
+
| {
|
|
166
|
+
statusKey: 'waiting_for_reply'
|
|
167
|
+
timeLimit?: never
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
interface CreateBoardWithStatusParams extends CreateBoardBaseParams {
|
|
171
|
+
initialStatus: InitialStatus
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
createBoardWithStatus(
|
|
175
|
+
params: CreateBoardWithStatusParams
|
|
176
|
+
): Promise<CreateBoardResponse>
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
- `scheduled_for_*` の場合は timeLimit が必須
|
|
180
|
+
- `waiting_for_reply` の場合は timeLimit は指定できません(型でも実行時でも防止)
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
### `createBoardWithStatusAndMessage(params)`
|
|
185
|
+
|
|
186
|
+
```ts
|
|
187
|
+
interface InitialGuestComment {
|
|
188
|
+
content: string
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
interface CreateBoardWithStatusAndMessageParams
|
|
192
|
+
extends CreateBoardBaseParams {
|
|
193
|
+
initialStatus: InitialStatus
|
|
194
|
+
initialGuestComment: InitialGuestComment
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
createBoardWithStatusAndMessage(
|
|
198
|
+
params: CreateBoardWithStatusAndMessageParams
|
|
199
|
+
): Promise<CreateBoardResponse>
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
初回のゲスト投稿までまとめて登録する場合に使います。
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
### `CreateBoardResponse`
|
|
207
|
+
|
|
208
|
+
```ts
|
|
209
|
+
interface CreateBoardResponse {
|
|
210
|
+
slug: string
|
|
211
|
+
hostURL: string
|
|
212
|
+
guestURL: string
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
- `slug` – ボードの識別子
|
|
217
|
+
- `hostURL` – ホスト(管理側)用 URL
|
|
218
|
+
- `guestURL` – ゲスト側 URL(メールに貼るなど)
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## Validation
|
|
223
|
+
|
|
224
|
+
このクライアントは、API 呼び出し前に以下の実行時チェックを行います:
|
|
225
|
+
|
|
226
|
+
- guest.email – 簡易メール形式チェック
|
|
227
|
+
- boardUniqueKey
|
|
228
|
+
- 空文字禁止
|
|
229
|
+
- 前後の空白禁止
|
|
230
|
+
- 空白文字(スペース・タブ・改行など)を含まない
|
|
231
|
+
- 最大 255 文字まで
|
|
232
|
+
- initialStatus.timeLimit
|
|
233
|
+
- scheduled_for_* の場合は必須
|
|
234
|
+
- YYYY-MM-DD 形式
|
|
235
|
+
- 実在する日付か確認(うるう年を含む)
|
|
236
|
+
|
|
237
|
+
バリデーションエラーの場合、API は呼び出されず Error が投げられます。
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## Development
|
|
242
|
+
|
|
243
|
+
ローカル開発用コマンド:
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
# 依存関係インストール
|
|
247
|
+
npm install
|
|
248
|
+
|
|
249
|
+
# テスト実行(1回)
|
|
250
|
+
npm run test
|
|
251
|
+
|
|
252
|
+
# テストをウォッチモードで実行
|
|
253
|
+
npm run test:watch
|
|
254
|
+
|
|
255
|
+
# ビルド
|
|
256
|
+
npm run build
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
リリース前チェック:
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
# テスト & ビルド
|
|
263
|
+
npm run test
|
|
264
|
+
npm run build
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
`npm publish` 時には自動的に `npm run test && npm run build` が実行されます。
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## License
|
|
272
|
+
|
|
273
|
+
MIT
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ChatEaseClientOptions, CreateBoardBaseParams, CreateBoardWithStatusParams, CreateBoardWithStatusAndMessageParams, CreateBoardResponse } from './types.js';
|
|
2
|
+
export declare class ChatEaseClient {
|
|
3
|
+
private readonly apiToken;
|
|
4
|
+
private readonly workspaceSlug;
|
|
5
|
+
private readonly baseUrl;
|
|
6
|
+
constructor(options: ChatEaseClientOptions);
|
|
7
|
+
createBoard(params: CreateBoardBaseParams): Promise<CreateBoardResponse>;
|
|
8
|
+
createBoardWithStatus(params: CreateBoardWithStatusParams): Promise<CreateBoardResponse>;
|
|
9
|
+
createBoardWithStatusAndMessage(params: CreateBoardWithStatusAndMessageParams): Promise<CreateBoardResponse>;
|
|
10
|
+
/**
|
|
11
|
+
* 実処理 + 共通バリデーション
|
|
12
|
+
*/
|
|
13
|
+
private _createBoard;
|
|
14
|
+
/**
|
|
15
|
+
* 呼び出しパラメータのバリデーション
|
|
16
|
+
* - email 形式チェック
|
|
17
|
+
* - boardUniqueKey 妥当性チェック
|
|
18
|
+
* - initialStatus があれば timeLimit を検証
|
|
19
|
+
*/
|
|
20
|
+
private validateParams;
|
|
21
|
+
private buildUrl;
|
|
22
|
+
}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { isValidBoardUniqueKey, isValidEmail, validateInitialStatus, } from './validators.js';
|
|
2
|
+
export class ChatEaseClient {
|
|
3
|
+
constructor(options) {
|
|
4
|
+
if (typeof window !== 'undefined') {
|
|
5
|
+
throw new Error('ChatEaseClient is for Node.js only. Do not use it in the browser (API token leak risk).');
|
|
6
|
+
}
|
|
7
|
+
if (!options.apiToken) {
|
|
8
|
+
throw new Error('ChatEaseClient: apiToken is required');
|
|
9
|
+
}
|
|
10
|
+
if (!options.workspaceSlug) {
|
|
11
|
+
throw new Error('ChatEaseClient: workspaceSlug is required');
|
|
12
|
+
}
|
|
13
|
+
this.apiToken = options.apiToken;
|
|
14
|
+
this.workspaceSlug = options.workspaceSlug;
|
|
15
|
+
this.baseUrl = options.baseUrl ?? 'https://chatease.jp';
|
|
16
|
+
if (typeof fetch !== 'function') {
|
|
17
|
+
throw new Error('ChatEaseClient requires global fetch (Node.js v18+).');
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
async createBoard(params) {
|
|
21
|
+
return this._createBoard(params);
|
|
22
|
+
}
|
|
23
|
+
async createBoardWithStatus(params) {
|
|
24
|
+
return this._createBoard(params);
|
|
25
|
+
}
|
|
26
|
+
async createBoardWithStatusAndMessage(params) {
|
|
27
|
+
return this._createBoard(params);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* 実処理 + 共通バリデーション
|
|
31
|
+
*/
|
|
32
|
+
async _createBoard(params) {
|
|
33
|
+
this.validateParams(params);
|
|
34
|
+
const body = {
|
|
35
|
+
workspaceSlug: this.workspaceSlug,
|
|
36
|
+
...params,
|
|
37
|
+
};
|
|
38
|
+
const res = await fetch(this.buildUrl('/api/v1/board'), {
|
|
39
|
+
method: 'POST',
|
|
40
|
+
headers: {
|
|
41
|
+
'Content-Type': 'application/json',
|
|
42
|
+
'X-Chatease-API-Token': this.apiToken,
|
|
43
|
+
},
|
|
44
|
+
body: JSON.stringify(body),
|
|
45
|
+
});
|
|
46
|
+
if (!res.ok) {
|
|
47
|
+
const text = await res.text().catch(() => '');
|
|
48
|
+
const message = [
|
|
49
|
+
`ChatEase API error: ${res.status} ${res.statusText}`,
|
|
50
|
+
text && `Body: ${text}`,
|
|
51
|
+
]
|
|
52
|
+
.filter(Boolean)
|
|
53
|
+
.join(' - ');
|
|
54
|
+
throw new Error(message);
|
|
55
|
+
}
|
|
56
|
+
const json = (await res.json());
|
|
57
|
+
return json;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* 呼び出しパラメータのバリデーション
|
|
61
|
+
* - email 形式チェック
|
|
62
|
+
* - boardUniqueKey 妥当性チェック
|
|
63
|
+
* - initialStatus があれば timeLimit を検証
|
|
64
|
+
*/
|
|
65
|
+
validateParams(params) {
|
|
66
|
+
const { guest, boardUniqueKey } = params;
|
|
67
|
+
if (!guest?.email) {
|
|
68
|
+
throw new Error('guest.email is required');
|
|
69
|
+
}
|
|
70
|
+
if (!isValidEmail(guest.email)) {
|
|
71
|
+
throw new Error(`guest.email is invalid: ${guest.email}`);
|
|
72
|
+
}
|
|
73
|
+
if (!isValidBoardUniqueKey(boardUniqueKey)) {
|
|
74
|
+
throw new Error(`boardUniqueKey is invalid. It must be a non-empty string without whitespace and <= 255 chars. Got: "${boardUniqueKey}"`);
|
|
75
|
+
}
|
|
76
|
+
if ('initialStatus' in params && params.initialStatus) {
|
|
77
|
+
validateInitialStatus(params.initialStatus);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
buildUrl(path) {
|
|
81
|
+
return `${this.baseUrl.replace(/\/+$/, '')}${path}`;
|
|
82
|
+
}
|
|
83
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export type ChatEaseStatusKey = 'scheduled_for_proof' | 'scheduled_for_response' | 'scheduled_for_completion' | 'waiting_for_reply';
|
|
2
|
+
type ScheduledStatusKey = 'scheduled_for_proof' | 'scheduled_for_response' | 'scheduled_for_completion';
|
|
3
|
+
type NonScheduledStatusKey = 'waiting_for_reply';
|
|
4
|
+
export type InitialStatus = {
|
|
5
|
+
statusKey: ScheduledStatusKey;
|
|
6
|
+
/**
|
|
7
|
+
* scheduled_for_* の場合は必須
|
|
8
|
+
* YYYY-MM-DD
|
|
9
|
+
*/
|
|
10
|
+
timeLimit: string;
|
|
11
|
+
} | {
|
|
12
|
+
statusKey: NonScheduledStatusKey;
|
|
13
|
+
/**
|
|
14
|
+
* scheduled 以外は timeLimit を指定させない
|
|
15
|
+
*/
|
|
16
|
+
timeLimit?: never;
|
|
17
|
+
};
|
|
18
|
+
export interface ChatEaseClientOptions {
|
|
19
|
+
apiToken: string;
|
|
20
|
+
workspaceSlug: string;
|
|
21
|
+
baseUrl?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface GuestInfo {
|
|
24
|
+
name: string;
|
|
25
|
+
email: string;
|
|
26
|
+
}
|
|
27
|
+
export interface InitialGuestComment {
|
|
28
|
+
content: string;
|
|
29
|
+
}
|
|
30
|
+
export interface CreateBoardBaseParams {
|
|
31
|
+
title: string;
|
|
32
|
+
guest: GuestInfo;
|
|
33
|
+
boardUniqueKey: string;
|
|
34
|
+
inReplyTo?: string;
|
|
35
|
+
}
|
|
36
|
+
export interface CreateBoardWithStatusParams extends CreateBoardBaseParams {
|
|
37
|
+
initialStatus: InitialStatus;
|
|
38
|
+
}
|
|
39
|
+
export interface CreateBoardWithStatusAndMessageParams extends CreateBoardBaseParams {
|
|
40
|
+
initialStatus: InitialStatus;
|
|
41
|
+
initialGuestComment: InitialGuestComment;
|
|
42
|
+
}
|
|
43
|
+
export interface CreateBoardRequestBody extends CreateBoardBaseParams {
|
|
44
|
+
workspaceSlug: string;
|
|
45
|
+
inReplyTo?: string;
|
|
46
|
+
initialStatus?: InitialStatus;
|
|
47
|
+
initialGuestComment?: InitialGuestComment;
|
|
48
|
+
}
|
|
49
|
+
export interface CreateBoardResponse {
|
|
50
|
+
slug: string;
|
|
51
|
+
hostURL: string;
|
|
52
|
+
guestURL: string;
|
|
53
|
+
}
|
|
54
|
+
export {};
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { InitialStatus } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* YYYY-MM-DD 形式 & 実在する日付かをチェック
|
|
4
|
+
*/
|
|
5
|
+
export declare function isValidISODate(dateStr: string): boolean;
|
|
6
|
+
/**
|
|
7
|
+
* メールアドレスの簡易バリデーション
|
|
8
|
+
* RFC完全準拠ではなく、実務的な最低限チェック。
|
|
9
|
+
* 「本気の検証」は呼び出し側に任せる。
|
|
10
|
+
*/
|
|
11
|
+
export declare function isValidEmail(email: string): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* boardUniqueKey のバリデーション
|
|
14
|
+
*
|
|
15
|
+
* ここは仕様に合わせて調整する想定。
|
|
16
|
+
* 現状は:
|
|
17
|
+
* - 空文字禁止
|
|
18
|
+
* - 前後空白を許可しない(trimして変化するならNG)
|
|
19
|
+
* - 制御文字・空白を含まない
|
|
20
|
+
* - 長さ 1〜255 文字
|
|
21
|
+
*/
|
|
22
|
+
export declare function isValidBoardUniqueKey(key: string): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* InitialStatus の timeLimit を検証
|
|
25
|
+
* scheduled_for_* のときは timeLimit 必須(型でも実行時でも保証)
|
|
26
|
+
*/
|
|
27
|
+
export declare function validateInitialStatus(status: InitialStatus): void;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// src/validators.ts
|
|
2
|
+
const ISO_DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/;
|
|
3
|
+
/**
|
|
4
|
+
* YYYY-MM-DD 形式 & 実在する日付かをチェック
|
|
5
|
+
*/
|
|
6
|
+
export function isValidISODate(dateStr) {
|
|
7
|
+
if (!ISO_DATE_REGEX.test(dateStr))
|
|
8
|
+
return false;
|
|
9
|
+
const [y, m, d] = dateStr.split('-').map(Number);
|
|
10
|
+
// UTC で日付オブジェクトを作成(タイムゾーン非依存)
|
|
11
|
+
const date = new Date(Date.UTC(y, m - 1, d));
|
|
12
|
+
return (date.getUTCFullYear() === y &&
|
|
13
|
+
date.getUTCMonth() === m - 1 &&
|
|
14
|
+
date.getUTCDate() === d);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* メールアドレスの簡易バリデーション
|
|
18
|
+
* RFC完全準拠ではなく、実務的な最低限チェック。
|
|
19
|
+
* 「本気の検証」は呼び出し側に任せる。
|
|
20
|
+
*/
|
|
21
|
+
export function isValidEmail(email) {
|
|
22
|
+
// かなり緩めのチェック(@の前後にそれなりの文字列があるか)
|
|
23
|
+
const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
24
|
+
return EMAIL_REGEX.test(email);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* boardUniqueKey のバリデーション
|
|
28
|
+
*
|
|
29
|
+
* ここは仕様に合わせて調整する想定。
|
|
30
|
+
* 現状は:
|
|
31
|
+
* - 空文字禁止
|
|
32
|
+
* - 前後空白を許可しない(trimして変化するならNG)
|
|
33
|
+
* - 制御文字・空白を含まない
|
|
34
|
+
* - 長さ 1〜255 文字
|
|
35
|
+
*/
|
|
36
|
+
export function isValidBoardUniqueKey(key) {
|
|
37
|
+
if (!key)
|
|
38
|
+
return false;
|
|
39
|
+
if (key.trim() !== key)
|
|
40
|
+
return false;
|
|
41
|
+
if (key.length > 255)
|
|
42
|
+
return false;
|
|
43
|
+
// 空白や制御文字を禁止(必要に応じて緩めてもOK)
|
|
44
|
+
const INVALID_CHARS_REGEX = /[\s]/;
|
|
45
|
+
if (INVALID_CHARS_REGEX.test(key))
|
|
46
|
+
return false;
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* InitialStatus の timeLimit を検証
|
|
51
|
+
* scheduled_for_* のときは timeLimit 必須(型でも実行時でも保証)
|
|
52
|
+
*/
|
|
53
|
+
export function validateInitialStatus(status) {
|
|
54
|
+
if ('timeLimit' in status) {
|
|
55
|
+
const { timeLimit } = status;
|
|
56
|
+
if (!timeLimit) {
|
|
57
|
+
throw new Error('initialStatus.timeLimit is required when statusKey is scheduled_for_*');
|
|
58
|
+
}
|
|
59
|
+
if (!isValidISODate(timeLimit)) {
|
|
60
|
+
throw new Error(`initialStatus.timeLimit must be a valid date in YYYY-MM-DD format. Got: ${timeLimit}`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bagooon/chatease-node-client",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Node.js-only client for ChatEase board API",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc",
|
|
19
|
+
"prepare": "npm run build",
|
|
20
|
+
"test": "vitest run",
|
|
21
|
+
"test:watch": "vitest",
|
|
22
|
+
"test:ui": "vitest --ui",
|
|
23
|
+
"prepublishOnly": "npm run test && npm run build"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"chatease",
|
|
27
|
+
"chat",
|
|
28
|
+
"board",
|
|
29
|
+
"api",
|
|
30
|
+
"node"
|
|
31
|
+
],
|
|
32
|
+
"author": "Hashimoto Giken",
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=18"
|
|
36
|
+
},
|
|
37
|
+
"browser": {
|
|
38
|
+
"./dist/index.js": false
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/node": "^25.3.0",
|
|
42
|
+
"@vitest/ui": "^4.0.18",
|
|
43
|
+
"typescript": "^5.9.3",
|
|
44
|
+
"vitest": "^4.0.18"
|
|
45
|
+
}
|
|
46
|
+
}
|