swallowkit 0.1.0-alpha.1
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/LICENSE +21 -0
- package/README.md +563 -0
- package/dist/api/rpc-handler.d.ts +71 -0
- package/dist/api/rpc-handler.d.ts.map +1 -0
- package/dist/api/rpc-handler.js +205 -0
- package/dist/api/rpc-handler.js.map +1 -0
- package/dist/cli/commands/build.d.ts +6 -0
- package/dist/cli/commands/build.d.ts.map +1 -0
- package/dist/cli/commands/build.js +193 -0
- package/dist/cli/commands/build.js.map +1 -0
- package/dist/cli/commands/dev.d.ts +3 -0
- package/dist/cli/commands/dev.d.ts.map +1 -0
- package/dist/cli/commands/dev.js +305 -0
- package/dist/cli/commands/dev.js.map +1 -0
- package/dist/cli/commands/generate.d.ts +4 -0
- package/dist/cli/commands/generate.d.ts.map +1 -0
- package/dist/cli/commands/generate.js +238 -0
- package/dist/cli/commands/generate.js.map +1 -0
- package/dist/cli/commands/index.d.ts +9 -0
- package/dist/cli/commands/index.d.ts.map +1 -0
- package/dist/cli/commands/index.js +18 -0
- package/dist/cli/commands/index.js.map +1 -0
- package/dist/cli/commands/init.d.ts +7 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +383 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/setup.d.ts +6 -0
- package/dist/cli/commands/setup.d.ts.map +1 -0
- package/dist/cli/commands/setup.js +254 -0
- package/dist/cli/commands/setup.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +32 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/core/config.d.ts +25 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +204 -0
- package/dist/core/config.js.map +1 -0
- package/dist/database/client.d.ts +46 -0
- package/dist/database/client.d.ts.map +1 -0
- package/dist/database/client.js +156 -0
- package/dist/database/client.js.map +1 -0
- package/dist/database/repository.d.ts +71 -0
- package/dist/database/repository.d.ts.map +1 -0
- package/dist/database/repository.js +89 -0
- package/dist/database/repository.js.map +1 -0
- package/dist/generator/api-generator.d.ts +53 -0
- package/dist/generator/api-generator.d.ts.map +1 -0
- package/dist/generator/api-generator.js +284 -0
- package/dist/generator/api-generator.js.map +1 -0
- package/dist/generator/schema-parser.d.ts +45 -0
- package/dist/generator/schema-parser.d.ts.map +1 -0
- package/dist/generator/schema-parser.js +198 -0
- package/dist/generator/schema-parser.js.map +1 -0
- package/dist/generator/templates/azure-functions.d.ts +15 -0
- package/dist/generator/templates/azure-functions.d.ts.map +1 -0
- package/dist/generator/templates/azure-functions.js +274 -0
- package/dist/generator/templates/azure-functions.js.map +1 -0
- package/dist/generator/templates/default-server-functions.d.ts +2 -0
- package/dist/generator/templates/default-server-functions.d.ts.map +1 -0
- package/dist/generator/templates/default-server-functions.js +67 -0
- package/dist/generator/templates/default-server-functions.js.map +1 -0
- package/dist/hooks/server-function-registry.d.ts +67 -0
- package/dist/hooks/server-function-registry.d.ts.map +1 -0
- package/dist/hooks/server-function-registry.js +153 -0
- package/dist/hooks/server-function-registry.js.map +1 -0
- package/dist/hooks/useQuery.d.ts +61 -0
- package/dist/hooks/useQuery.d.ts.map +1 -0
- package/dist/hooks/useQuery.js +147 -0
- package/dist/hooks/useQuery.js.map +1 -0
- package/dist/hooks/useServerFn.d.ts +27 -0
- package/dist/hooks/useServerFn.d.ts.map +1 -0
- package/dist/hooks/useServerFn.js +119 -0
- package/dist/hooks/useServerFn.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +73 -0
- package/dist/index.js.map +1 -0
- package/dist/schemas/example.d.ts +657 -0
- package/dist/schemas/example.d.ts.map +1 -0
- package/dist/schemas/example.js +133 -0
- package/dist/schemas/example.js.map +1 -0
- package/dist/server/todo-functions.d.ts +21 -0
- package/dist/server/todo-functions.d.ts.map +1 -0
- package/dist/server/todo-functions.js +121 -0
- package/dist/server/todo-functions.js.map +1 -0
- package/dist/types/index.d.ts +53 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +6 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +68 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Takumasa Hirabayashi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,563 @@
|
|
|
1
|
+
# SwallowKit (暫定版)
|
|
2
|
+
|
|
3
|
+
Azure Static Web Apps + Cosmos DB 専用フレームワーク
|
|
4
|
+
|
|
5
|
+
> **注意**: これは暫定版のドキュメントです。API や機能は今後変更される可能性があります。
|
|
6
|
+
|
|
7
|
+
## 🚀 特徴
|
|
8
|
+
|
|
9
|
+
- **Cosmos DB 標準搭載**: Cosmos DB をデフォルトデータベースとして採用
|
|
10
|
+
- **React Hooks ベース**: `useServerFn` / `callServerFn` でサーバー関数を簡単に呼び出し
|
|
11
|
+
- **型安全**: TypeScript による完全な型安全性
|
|
12
|
+
- **自動セットアップ**: 開発環境起動時に Cosmos DB を自動セットアップ
|
|
13
|
+
- **Azure 最適化**: Azure Static Web Apps + Azure Functions v4 に最適化
|
|
14
|
+
- **開発者体験**: シンプルなコマンドで開発開始
|
|
15
|
+
|
|
16
|
+
## 📋 前提条件
|
|
17
|
+
|
|
18
|
+
- Node.js 22.x
|
|
19
|
+
- Azure Cosmos DB Emulator (ローカル開発用)
|
|
20
|
+
- Windows: [公式サイト](https://aka.ms/cosmosdb-emulator)からインストール
|
|
21
|
+
- Docker: `docker run -p 8081:8081 mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator`
|
|
22
|
+
|
|
23
|
+
## 📦 インストール
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install swallowkit
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## 🛠️ クイックスタート
|
|
30
|
+
|
|
31
|
+
### 1. プロジェクトの初期化
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npx swallowkit init my-todo-app
|
|
35
|
+
cd my-todo-app
|
|
36
|
+
npm install
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
これにより以下が生成されます:
|
|
40
|
+
- `src/` - React アプリケーション (Vite + React + TypeScript)
|
|
41
|
+
- `src/serverFns.ts` - サーバー関数の型定義 (クライアント側スタブ)
|
|
42
|
+
- `swallowkit.config.json` - SwallowKit 設定ファイル
|
|
43
|
+
|
|
44
|
+
### 2. Cosmos DB Emulator の起動
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# Windowsの場合: スタートメニューから起動
|
|
48
|
+
# Dockerの場合:
|
|
49
|
+
docker run -p 8081:8081 mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### 3. 開発環境の起動
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
npx swallowkit dev
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
このコマンドは:
|
|
59
|
+
1. Cosmos DB Emulator の起動確認
|
|
60
|
+
2. Cosmos DB のデータベース・コンテナの自動作成 (冪等性あり)
|
|
61
|
+
3. Azure Functions API の自動ビルド
|
|
62
|
+
4. Vite 開発サーバーの起動
|
|
63
|
+
5. SWA CLI による統合環境の起動
|
|
64
|
+
|
|
65
|
+
開発サーバーが起動したら、`http://localhost:4280` でアプリにアクセスできます。
|
|
66
|
+
|
|
67
|
+
## 📝 サーバー関数の実装
|
|
68
|
+
|
|
69
|
+
### クライアント側の型定義 (`src/serverFns.ts`)
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
// クライアント側のスタブ - ブラウザでは実行されない
|
|
73
|
+
interface Todo {
|
|
74
|
+
id: string;
|
|
75
|
+
text: string;
|
|
76
|
+
completed: boolean;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export async function getTodos(): Promise<Todo[]> {
|
|
80
|
+
throw new Error("This is a server function and should be called via useServerFn");
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export async function addTodo({ text }: { text: string }): Promise<Todo> {
|
|
84
|
+
throw new Error("This is a server function and should be called via useServerFn");
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export async function deleteTodo({ id }: { id: string }): Promise<{ success: boolean }> {
|
|
88
|
+
throw new Error("This is a server function and should be called via useServerFn");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export async function toggleTodo({ id }: { id: string }): Promise<Todo | null> {
|
|
92
|
+
throw new Error("This is a server function and should be called via useServerFn");
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### API の生成
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
npx swallowkit generate
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
これにより `api/` ディレクトリに以下が生成されます:
|
|
103
|
+
- `api/src/shared/server-functions.ts` - Cosmos DB を使った実装
|
|
104
|
+
- `api/src/functions/rpc.ts` - RPC エンドポイント (`/api/_swallowkit`)
|
|
105
|
+
- Azure Functions v4 の設定ファイル
|
|
106
|
+
|
|
107
|
+
**重要**: `server-functions.ts` は自動生成されますが、**ビジネスロジックを実装するファイル**です。
|
|
108
|
+
初回生成後はテンプレートをカスタマイズして使用してください。
|
|
109
|
+
|
|
110
|
+
### サーバー側の実装例 (`api/src/shared/server-functions.ts`)
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
import { CosmosClient } from '@azure/cosmos';
|
|
114
|
+
|
|
115
|
+
// Cosmos DB クライアントの初期化
|
|
116
|
+
const endpoint = process.env.COSMOS_ENDPOINT || 'http://localhost:8081';
|
|
117
|
+
const key = process.env.COSMOS_KEY || 'C2y6yDjf5/R+...'; // Emulator key
|
|
118
|
+
const client = new CosmosClient({ endpoint, key });
|
|
119
|
+
|
|
120
|
+
const database = client.database('swallowkit-db');
|
|
121
|
+
const container = database.container('todos');
|
|
122
|
+
|
|
123
|
+
interface Todo {
|
|
124
|
+
id: string;
|
|
125
|
+
text: string;
|
|
126
|
+
completed: boolean;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export async function getTodos(): Promise<Todo[]> {
|
|
130
|
+
const { resources } = await container.items.query('SELECT * FROM c').fetchAll();
|
|
131
|
+
return resources as Todo[];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export async function addTodo({ text }: { text: string }): Promise<Todo> {
|
|
135
|
+
const newTodo: Todo = {
|
|
136
|
+
id: Date.now().toString(),
|
|
137
|
+
text,
|
|
138
|
+
completed: false,
|
|
139
|
+
};
|
|
140
|
+
const { resource } = await container.items.create(newTodo);
|
|
141
|
+
return resource as Todo;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export async function deleteTodo({ id }: { id: string }): Promise<{ success: boolean }> {
|
|
145
|
+
await container.item(id, id).delete();
|
|
146
|
+
return { success: true };
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export async function toggleTodo({ id }: { id: string }): Promise<Todo | null> {
|
|
150
|
+
const { resource: todo } = await container.item(id, id).read<Todo>();
|
|
151
|
+
if (todo) {
|
|
152
|
+
todo.completed = !todo.completed;
|
|
153
|
+
const { resource } = await container.item(id, id).replace(todo);
|
|
154
|
+
return resource as Todo;
|
|
155
|
+
}
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## 🎯 React での使用
|
|
161
|
+
|
|
162
|
+
### クエリ用: `useServerFn`
|
|
163
|
+
|
|
164
|
+
データ取得など、状態管理が必要な操作に使用:
|
|
165
|
+
|
|
166
|
+
```tsx
|
|
167
|
+
import { useServerFn } from "swallowkit";
|
|
168
|
+
import { getTodos } from "./serverFns";
|
|
169
|
+
|
|
170
|
+
function TodoList() {
|
|
171
|
+
const { data: todos, loading, error, refetch } = useServerFn(getTodos, []);
|
|
172
|
+
|
|
173
|
+
if (loading) return <div>読み込み中...</div>;
|
|
174
|
+
if (error) return <div>エラー: {error.message}</div>;
|
|
175
|
+
|
|
176
|
+
return (
|
|
177
|
+
<div>
|
|
178
|
+
<ul>
|
|
179
|
+
{todos?.map((todo) => (
|
|
180
|
+
<li key={todo.id}>{todo.text}</li>
|
|
181
|
+
))}
|
|
182
|
+
</ul>
|
|
183
|
+
<button onClick={refetch}>再読み込み</button>
|
|
184
|
+
</div>
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### ミューテーション用: `callServerFn`
|
|
190
|
+
|
|
191
|
+
追加・更新・削除など、状態管理が不要な操作に使用:
|
|
192
|
+
|
|
193
|
+
```tsx
|
|
194
|
+
import { useServerFn, callServerFn } from "swallowkit";
|
|
195
|
+
import { getTodos, addTodo, deleteTodo, toggleTodo } from "./serverFns";
|
|
196
|
+
|
|
197
|
+
function TodoApp() {
|
|
198
|
+
const [newTodoText, setNewTodoText] = useState("");
|
|
199
|
+
const { data: todos, loading, error, refetch } = useServerFn(getTodos, []);
|
|
200
|
+
|
|
201
|
+
const handleAddTodo = async () => {
|
|
202
|
+
if (!newTodoText.trim()) return;
|
|
203
|
+
|
|
204
|
+
await callServerFn(addTodo, { text: newTodoText });
|
|
205
|
+
setNewTodoText("");
|
|
206
|
+
refetch(); // クエリを再実行して最新データを取得
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
const handleToggleTodo = async (id: string) => {
|
|
210
|
+
await callServerFn(toggleTodo, { id });
|
|
211
|
+
refetch();
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
const handleDeleteTodo = async (id: string) => {
|
|
215
|
+
await callServerFn(deleteTodo, { id });
|
|
216
|
+
refetch();
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
// ... レンダリング
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
## 📚 API リファレンス
|
|
224
|
+
|
|
225
|
+
### `useServerFn<TResult>(serverFn, args, options?)`
|
|
226
|
+
|
|
227
|
+
**パラメータ:**
|
|
228
|
+
- `serverFn`: サーバー関数
|
|
229
|
+
- `args`: 関数の引数の配列
|
|
230
|
+
- `options?`: オプション設定
|
|
231
|
+
|
|
232
|
+
**戻り値:**
|
|
233
|
+
```typescript
|
|
234
|
+
{
|
|
235
|
+
data: TResult | null;
|
|
236
|
+
loading: boolean;
|
|
237
|
+
error: Error | null;
|
|
238
|
+
refetch: () => Promise<void>;
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
**使用例:**
|
|
243
|
+
```typescript
|
|
244
|
+
const { data, loading, error, refetch } = useServerFn(getTodos, []);
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### `callServerFn<TArgs, TResult>(serverFn, ...args)`
|
|
248
|
+
|
|
249
|
+
**パラメータ:**
|
|
250
|
+
- `serverFn`: サーバー関数
|
|
251
|
+
- `...args`: 関数の引数
|
|
252
|
+
|
|
253
|
+
**戻り値:**
|
|
254
|
+
- `Promise<TResult>`: サーバー関数の実行結果
|
|
255
|
+
|
|
256
|
+
**使用例:**
|
|
257
|
+
```typescript
|
|
258
|
+
const result = await callServerFn(addTodo, { text: "新しいTodo" });
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
## 🔧 CLI コマンド
|
|
262
|
+
|
|
263
|
+
### `swallowkit init <project-name>`
|
|
264
|
+
|
|
265
|
+
新しい SwallowKit プロジェクトを作成します。
|
|
266
|
+
|
|
267
|
+
```bash
|
|
268
|
+
npx swallowkit init my-app
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### `swallowkit dev`
|
|
272
|
+
|
|
273
|
+
統合開発環境を起動します:
|
|
274
|
+
- Cosmos DB の自動セットアップ
|
|
275
|
+
- Azure Functions の自動ビルド
|
|
276
|
+
- Vite + SWA CLI の統合サーバー起動
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
npx swallowkit dev
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
**オプション:**
|
|
283
|
+
- `--port <port>`: SWA CLI のポート (デフォルト: 4280)
|
|
284
|
+
- `--api-port <port>`: Azure Functions のポート (デフォルト: 7071)
|
|
285
|
+
- `--host <host>`: ホスト名 (デフォルト: localhost)
|
|
286
|
+
- `--open`: ブラウザを自動で開く
|
|
287
|
+
|
|
288
|
+
### `swallowkit generate`
|
|
289
|
+
|
|
290
|
+
`src/serverFns.ts` から Azure Functions API を生成します。
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
npx swallowkit generate
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
**オプション:**
|
|
297
|
+
- `--output <dir>`: 出力ディレクトリ (デフォルト: ./api)
|
|
298
|
+
- `--force`: 既存ファイルを上書き
|
|
299
|
+
|
|
300
|
+
### `swallowkit setup`
|
|
301
|
+
|
|
302
|
+
開発環境の依存関係をチェックします:
|
|
303
|
+
- Azure CLI
|
|
304
|
+
- Azure Static Web Apps CLI
|
|
305
|
+
- Cosmos DB Emulator
|
|
306
|
+
|
|
307
|
+
```bash
|
|
308
|
+
npx swallowkit setup
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
## 🔧 設定ファイル
|
|
312
|
+
|
|
313
|
+
## 🔧 設定ファイル
|
|
314
|
+
|
|
315
|
+
### `swallowkit.config.json`
|
|
316
|
+
|
|
317
|
+
```json
|
|
318
|
+
{
|
|
319
|
+
"database": {
|
|
320
|
+
"type": "cosmos",
|
|
321
|
+
"endpoint": "http://localhost:8081",
|
|
322
|
+
"key": "C2y6yDjf5/R+...",
|
|
323
|
+
"databaseName": "swallowkit-db"
|
|
324
|
+
},
|
|
325
|
+
"api": {
|
|
326
|
+
"endpoint": "/api/_swallowkit"
|
|
327
|
+
},
|
|
328
|
+
"functions": {
|
|
329
|
+
"outputDir": "api"
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
**プロパティ:**
|
|
335
|
+
- `database.type`: データベースタイプ (現在は `"cosmos"` のみ)
|
|
336
|
+
- `database.endpoint`: Cosmos DB エンドポイント
|
|
337
|
+
- `database.key`: Cosmos DB アクセスキー
|
|
338
|
+
- `database.databaseName`: データベース名
|
|
339
|
+
- `api.endpoint`: RPC エンドポイントのパス
|
|
340
|
+
- `functions.outputDir`: Azure Functions の出力ディレクトリ
|
|
341
|
+
|
|
342
|
+
### 環境変数 (`api/local.settings.json`)
|
|
343
|
+
|
|
344
|
+
```json
|
|
345
|
+
{
|
|
346
|
+
"IsEncrypted": false,
|
|
347
|
+
"Values": {
|
|
348
|
+
"FUNCTIONS_WORKER_RUNTIME": "node",
|
|
349
|
+
"FUNCTIONS_WORKER_RUNTIME_VERSION": "~22",
|
|
350
|
+
"AzureWebJobsStorage": "",
|
|
351
|
+
"COSMOS_ENDPOINT": "http://localhost:8081",
|
|
352
|
+
"COSMOS_KEY": "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="
|
|
353
|
+
},
|
|
354
|
+
"Host": {
|
|
355
|
+
"CORS": "*",
|
|
356
|
+
"LocalHttpPort": 7071
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
## 🏗️ アーキテクチャ
|
|
362
|
+
|
|
363
|
+
### クライアント・サーバー分離
|
|
364
|
+
|
|
365
|
+
```
|
|
366
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
367
|
+
│ クライアント (Browser) │
|
|
368
|
+
│ │
|
|
369
|
+
│ src/App.tsx │
|
|
370
|
+
│ ↓ import │
|
|
371
|
+
│ src/serverFns.ts (型定義スタブ) │
|
|
372
|
+
│ ↓ useServerFn / callServerFn │
|
|
373
|
+
│ swallowkit (hooks/useServerFn.ts) │
|
|
374
|
+
│ ↓ POST /api/_swallowkit │
|
|
375
|
+
└──────────────────────────────────────────────────────────────┘
|
|
376
|
+
│
|
|
377
|
+
│ HTTP Request
|
|
378
|
+
↓
|
|
379
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
380
|
+
│ サーバー (Azure Functions v4) │
|
|
381
|
+
│ │
|
|
382
|
+
│ api/src/functions/rpc.ts │
|
|
383
|
+
│ ↓ import │
|
|
384
|
+
│ api/src/shared/server-functions.ts (Cosmos DB実装) │
|
|
385
|
+
│ ↓ @azure/cosmos │
|
|
386
|
+
│ Cosmos DB │
|
|
387
|
+
└─────────────────────────────────────────────────────────────┘
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
### データフロー
|
|
391
|
+
|
|
392
|
+
1. **クエリ (useServerFn)**
|
|
393
|
+
- コンポーネントマウント時に自動実行
|
|
394
|
+
- ローディング状態を管理
|
|
395
|
+
- データをキャッシュ
|
|
396
|
+
- `refetch()` で再実行可能
|
|
397
|
+
|
|
398
|
+
2. **ミューテーション (callServerFn)**
|
|
399
|
+
- イベントハンドラから明示的に呼び出し
|
|
400
|
+
- 状態管理なし
|
|
401
|
+
- 完了後に `refetch()` を呼び出してクエリを更新
|
|
402
|
+
|
|
403
|
+
### Cosmos DB 自動セットアップ
|
|
404
|
+
|
|
405
|
+
`swallowkit dev` コマンド実行時:
|
|
406
|
+
|
|
407
|
+
```typescript
|
|
408
|
+
// dev コマンドの処理フロー
|
|
409
|
+
1. Cosmos DB Emulator の起動確認
|
|
410
|
+
2. CosmosClient で接続
|
|
411
|
+
3. database.createIfNotExists('swallowkit-db')
|
|
412
|
+
4. container.createIfNotExists('todos', {
|
|
413
|
+
partitionKey: {
|
|
414
|
+
paths: ['/id'],
|
|
415
|
+
kind: PartitionKeyKind.Hash
|
|
416
|
+
}
|
|
417
|
+
})
|
|
418
|
+
5. Azure Functions API のビルド
|
|
419
|
+
6. Vite + SWA CLI の起動
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
## 📁 プロジェクト構造
|
|
423
|
+
|
|
424
|
+
```
|
|
425
|
+
my-app/
|
|
426
|
+
├── src/
|
|
427
|
+
│ ├── App.tsx # React アプリケーション
|
|
428
|
+
│ ├── serverFns.ts # サーバー関数の型定義 (クライアント側)
|
|
429
|
+
│ ├── index.tsx # エントリーポイント
|
|
430
|
+
│ └── index.css # スタイル
|
|
431
|
+
├── api/ # Azure Functions (自動生成)
|
|
432
|
+
│ ├── src/
|
|
433
|
+
│ │ ├── functions/
|
|
434
|
+
│ │ │ ├── rpc.ts # RPC エンドポイント
|
|
435
|
+
│ │ │ └── crud.ts # CRUD エンドポイント (未使用)
|
|
436
|
+
│ │ └── shared/
|
|
437
|
+
│ │ └── server-functions.ts # サーバー側実装 (Cosmos DB)
|
|
438
|
+
│ ├── host.json
|
|
439
|
+
│ ├── local.settings.json
|
|
440
|
+
│ ├── tsconfig.json
|
|
441
|
+
│ └── package.json
|
|
442
|
+
├── swallowkit.config.json # SwallowKit 設定
|
|
443
|
+
├── staticwebapp.config.json # Azure SWA 設定
|
|
444
|
+
├── package.json
|
|
445
|
+
└── vite.config.ts
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
## 🚨 重要な注意事項
|
|
449
|
+
|
|
450
|
+
### 1. サーバー関数の戻り値
|
|
451
|
+
|
|
452
|
+
**❌ NG: `Promise<void>`**
|
|
453
|
+
```typescript
|
|
454
|
+
export async function deleteTodo({ id }: { id: string }): Promise<void> {
|
|
455
|
+
await container.item(id, id).delete();
|
|
456
|
+
// JSON レスポンスがないため RPC 呼び出しが失敗
|
|
457
|
+
}
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
**✅ OK: 必ず値を返す**
|
|
461
|
+
```typescript
|
|
462
|
+
export async function deleteTodo({ id }: { id: string }): Promise<{ success: boolean }> {
|
|
463
|
+
await container.item(id, id).delete();
|
|
464
|
+
return { success: true }; // JSON レスポンスを返す
|
|
465
|
+
}
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
### 2. パーティションキーの指定
|
|
469
|
+
|
|
470
|
+
Cosmos DB Emulator では `kind: PartitionKeyKind.Hash` の明示が必須:
|
|
471
|
+
|
|
472
|
+
```typescript
|
|
473
|
+
await database.containers.createIfNotExists({
|
|
474
|
+
id: 'todos',
|
|
475
|
+
partitionKey: {
|
|
476
|
+
paths: ['/id'],
|
|
477
|
+
kind: PartitionKeyKind.Hash // 必須!
|
|
478
|
+
}
|
|
479
|
+
});
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
### 3. クライアント・サーバーの分離
|
|
483
|
+
|
|
484
|
+
- `src/serverFns.ts` - **クライアント側の型定義のみ** (throw Error)
|
|
485
|
+
- `api/src/shared/server-functions.ts` - **サーバー側の実装** (Cosmos DB アクセス)
|
|
486
|
+
|
|
487
|
+
この2つは **別ファイル** です。混同しないでください。
|
|
488
|
+
|
|
489
|
+
### 4. generateコマンドの動作
|
|
490
|
+
|
|
491
|
+
`swallowkit generate` は:
|
|
492
|
+
- `src/serverFns.ts` がクライアントスタブ (throw Error を含む) の場合
|
|
493
|
+
→ デフォルトの Cosmos DB テンプレートを使用
|
|
494
|
+
- `src/serverFns.ts` が既に実装を含む場合
|
|
495
|
+
→ その実装を `api/src/shared/server-functions.ts` にコピー
|
|
496
|
+
|
|
497
|
+
## 🐛 トラブルシューティング
|
|
498
|
+
|
|
499
|
+
### Cosmos DB Emulator が起動しない
|
|
500
|
+
|
|
501
|
+
**Windows:**
|
|
502
|
+
```bash
|
|
503
|
+
# スタートメニューから "Azure Cosmos DB Emulator" を起動
|
|
504
|
+
# または、サービスから起動
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
**Docker:**
|
|
508
|
+
```bash
|
|
509
|
+
docker run -p 8081:8081 mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
### パーティションキーエラー
|
|
513
|
+
|
|
514
|
+
`PartitionKeyKind.Hash` を指定してください:
|
|
515
|
+
|
|
516
|
+
```typescript
|
|
517
|
+
import { CosmosClient, PartitionKeyKind } from '@azure/cosmos';
|
|
518
|
+
|
|
519
|
+
await database.containers.createIfNotExists({
|
|
520
|
+
id: 'your-container',
|
|
521
|
+
partitionKey: {
|
|
522
|
+
paths: ['/id'],
|
|
523
|
+
kind: PartitionKeyKind.Hash
|
|
524
|
+
}
|
|
525
|
+
});
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
### API が古い実装のまま
|
|
529
|
+
|
|
530
|
+
`generate --force` で強制的に再生成:
|
|
531
|
+
|
|
532
|
+
```bash
|
|
533
|
+
npx swallowkit generate --force
|
|
534
|
+
cd api
|
|
535
|
+
npm run build
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
## 🎯 今後の予定 (TODO)
|
|
539
|
+
|
|
540
|
+
- [ ] Zod スキーマ統合
|
|
541
|
+
- [ ] 認証・認可機能
|
|
542
|
+
- [ ] ファイルアップロード機能
|
|
543
|
+
- [ ] リアルタイム通信 (SignalR)
|
|
544
|
+
- [ ] デプロイコマンド (`swallowkit deploy`)
|
|
545
|
+
- [ ] テストユーティリティ
|
|
546
|
+
- [ ] 本番環境用の設定管理
|
|
547
|
+
|
|
548
|
+
## 🤝 コントリビューション
|
|
549
|
+
|
|
550
|
+
このプロジェクトは開発中です。フィードバックや提案を歓迎します!
|
|
551
|
+
|
|
552
|
+
## 📄 ライセンス
|
|
553
|
+
|
|
554
|
+
MIT
|
|
555
|
+
|
|
556
|
+
## 🔗 関連リンク
|
|
557
|
+
|
|
558
|
+
- [Azure Static Web Apps](https://azure.microsoft.com/ja-jp/services/app-service/static/)
|
|
559
|
+
- [Azure Functions](https://azure.microsoft.com/ja-jp/services/functions/)
|
|
560
|
+
- [Azure Cosmos DB](https://azure.microsoft.com/ja-jp/services/cosmos-db/)
|
|
561
|
+
- [React](https://reactjs.org/)
|
|
562
|
+
- [Vite](https://vitejs.dev/)
|
|
563
|
+
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { IncomingMessage, ServerResponse } from 'http';
|
|
2
|
+
export interface RpcRequest {
|
|
3
|
+
fnName: string;
|
|
4
|
+
args: any[];
|
|
5
|
+
}
|
|
6
|
+
export interface RpcResponse {
|
|
7
|
+
success: boolean;
|
|
8
|
+
data?: any;
|
|
9
|
+
error?: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* SwallowKit RPC APIハンドラー
|
|
13
|
+
* useServerFnからの呼び出しを処理
|
|
14
|
+
*/
|
|
15
|
+
export declare class RpcHandler {
|
|
16
|
+
private serverFunctions;
|
|
17
|
+
/**
|
|
18
|
+
* サーバー関数を登録
|
|
19
|
+
*/
|
|
20
|
+
registerFunction(name: string, fn: Function): void;
|
|
21
|
+
/**
|
|
22
|
+
* 複数のサーバー関数を一括登録
|
|
23
|
+
*/
|
|
24
|
+
registerFunctions(functions: Record<string, Function>): void;
|
|
25
|
+
/**
|
|
26
|
+
* Express.js スタイルのミドルウェア
|
|
27
|
+
*/
|
|
28
|
+
expressMiddleware(): (req: any, res: any, next?: any) => Promise<any>;
|
|
29
|
+
/**
|
|
30
|
+
* Next.js API Routes 対応
|
|
31
|
+
*/
|
|
32
|
+
nextApiHandler(): (req: any, res: any) => Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Azure Static Web Apps API 対応
|
|
35
|
+
*/
|
|
36
|
+
azureStaticWebAppsHandler(): (context: any, req: any) => Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Node.js http サーバー対応
|
|
39
|
+
*/
|
|
40
|
+
nodeHttpHandler(): (req: IncomingMessage, res: ServerResponse) => Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* リクエストを処理
|
|
43
|
+
*/
|
|
44
|
+
private handleRequest;
|
|
45
|
+
/**
|
|
46
|
+
* 成功レスポンスを送信
|
|
47
|
+
*/
|
|
48
|
+
private sendSuccess;
|
|
49
|
+
/**
|
|
50
|
+
* エラーレスポンスを送信
|
|
51
|
+
*/
|
|
52
|
+
private sendError;
|
|
53
|
+
/**
|
|
54
|
+
* Node.js リクエストボディをパース
|
|
55
|
+
*/
|
|
56
|
+
private parseRequestBody;
|
|
57
|
+
/**
|
|
58
|
+
* 登録された関数一覧を取得
|
|
59
|
+
*/
|
|
60
|
+
getRegisteredFunctions(): string[];
|
|
61
|
+
/**
|
|
62
|
+
* 関数の登録を削除
|
|
63
|
+
*/
|
|
64
|
+
unregisterFunction(name: string): boolean;
|
|
65
|
+
/**
|
|
66
|
+
* 全ての関数登録をクリア
|
|
67
|
+
*/
|
|
68
|
+
clearFunctions(): void;
|
|
69
|
+
}
|
|
70
|
+
export declare const defaultRpcHandler: RpcHandler;
|
|
71
|
+
//# sourceMappingURL=rpc-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rpc-handler.d.ts","sourceRoot":"","sources":["../../src/api/rpc-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,MAAM,CAAC;AAEvD,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,GAAG,EAAE,CAAC;CACb;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,eAAe,CAAoC;IAE3D;;OAEG;IACH,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,GAAG,IAAI;IAIlD;;OAEG;IACH,iBAAiB,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,IAAI;IAM5D;;OAEG;IACH,iBAAiB,KACD,KAAK,GAAG,EAAE,KAAK,GAAG,EAAE,OAAO,GAAG;IAqB9C;;OAEG;IACH,cAAc,KACE,KAAK,GAAG,EAAE,KAAK,GAAG;IAclC;;OAEG;IACH,yBAAyB,KACT,SAAS,GAAG,EAAE,KAAK,GAAG;IA2BtC;;OAEG;IACH,eAAe,KACC,KAAK,eAAe,EAAE,KAAK,cAAc;IAezD;;OAEG;YACW,aAAa;IAiB3B;;OAEG;IACH,OAAO,CAAC,WAAW;IAcnB;;OAEG;IACH,OAAO,CAAC,SAAS;IAcjB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAoBxB;;OAEG;IACH,sBAAsB,IAAI,MAAM,EAAE;IAIlC;;OAEG;IACH,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAIzC;;OAEG;IACH,cAAc,IAAI,IAAI;CAGvB;AAGD,eAAO,MAAM,iBAAiB,YAAmB,CAAC"}
|