@qmuse/appwrite-runtime-sdk 1.0.4-dev.1 → 1.0.5-dev.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/README.md +444 -52
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/portable.d.ts +6 -0
- package/dist/portable.js +379 -0
- package/dist/runtime/AppwriteSessionCoordinator.js +21 -36
- package/dist/runtime/MutationAuditReporter.js +2 -2
- package/dist/runtime/utils.d.ts +1 -0
- package/dist/runtime/utils.js +21 -2
- package/dist/types.d.ts +10 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,98 +1,490 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @qmuse/appwrite-runtime-sdk
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
QMuse 应用访问 Appwrite 的运行时 SDK,提供统一的运行时初始化、用户 Session 管理和 TablesDB 数据操作能力。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
SDK 支持两类应用:
|
|
6
|
+
|
|
7
|
+
| 应用类型 | 接入方式 | 适用平台 |
|
|
8
|
+
| -------------- | -------------------------------- | ---------------------------- |
|
|
9
|
+
| React Web 应用 | 配合 Appwrite Web SDK 创建客户端 | 浏览器、QMuse H5 预览 |
|
|
10
|
+
| Taro 应用 | 使用 SDK 提供的跨端客户端 | H5、支付宝小程序、微信小程序 |
|
|
11
|
+
|
|
12
|
+
## 安装
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install @qmuse/appwrite-runtime-sdk appwrite@24.1.1
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
在本地仓库联调 SDK 时,可以在应用的 `package.json` 中引用源码包:
|
|
19
|
+
|
|
20
|
+
```json
|
|
21
|
+
{
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@qmuse/appwrite-runtime-sdk": "file:../../appwrite-runtime-sdk",
|
|
24
|
+
"appwrite": "24.1.1"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## 运行时上下文
|
|
30
|
+
|
|
31
|
+
React 和 Taro 应用都需要向 SDK 提供以下 QMuse 运行时信息:
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
interface QmuseRuntimeContext {
|
|
35
|
+
appId: string;
|
|
36
|
+
env: 'dev' | 'prod';
|
|
37
|
+
domain: string;
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
| 字段 | 说明 |
|
|
42
|
+
| -------- | --------------------------------------------------------- |
|
|
43
|
+
| `appId` | 当前 QMuse 应用 ID |
|
|
44
|
+
| `env` | 当前运行环境 |
|
|
45
|
+
| `domain` | QMuse Runtime 服务域名,例如 `https://appio-pre.qmuse.cn` |
|
|
46
|
+
|
|
47
|
+
用户信息通过 `getQmuseLoginUserId()` 单独提供。已登录时返回 QMuse 用户 ID,未登录时返回 `null`。
|
|
48
|
+
|
|
49
|
+
`appVersionId` 不是运行时初始化或 Appwrite Custom Token 所需参数,不需要注入或传给 SDK。
|
|
50
|
+
|
|
51
|
+
## React 应用
|
|
52
|
+
|
|
53
|
+
React Web 应用使用 Appwrite Web SDK 提供的 `Client`、`Account` 和 `TablesDB`。
|
|
54
|
+
|
|
55
|
+
### 1. 声明宿主环境
|
|
56
|
+
|
|
57
|
+
在项目的全局类型文件中声明 QMuse 注入的环境:
|
|
6
58
|
|
|
7
59
|
```ts
|
|
8
|
-
|
|
9
|
-
|
|
60
|
+
// src/types/global.d.ts
|
|
61
|
+
interface Window {
|
|
62
|
+
__MUSE__: {
|
|
63
|
+
appId: string;
|
|
64
|
+
env: 'dev' | 'prod';
|
|
65
|
+
domain: string;
|
|
66
|
+
};
|
|
67
|
+
__TERN__?: {
|
|
68
|
+
user?: {
|
|
69
|
+
clientUser?: {
|
|
70
|
+
userId?: string;
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
```
|
|
10
76
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
77
|
+
### 2. 创建应用级单例
|
|
78
|
+
|
|
79
|
+
在统一的服务模块中创建 Runtime,并向业务代码导出所需方法:
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
// src/services/appwrite.ts
|
|
83
|
+
import {
|
|
84
|
+
Account,
|
|
85
|
+
Client,
|
|
86
|
+
ID,
|
|
87
|
+
Permission,
|
|
88
|
+
Query,
|
|
89
|
+
Role,
|
|
90
|
+
TablesDB,
|
|
91
|
+
} from 'appwrite';
|
|
92
|
+
import {
|
|
93
|
+
createQmuseAppwriteRuntime,
|
|
94
|
+
type AppwriteAccountLike,
|
|
95
|
+
type Models,
|
|
96
|
+
type QmuseRuntimeContext,
|
|
97
|
+
} from '@qmuse/appwrite-runtime-sdk';
|
|
98
|
+
|
|
99
|
+
const client = new Client();
|
|
100
|
+
const account = new Account(client);
|
|
101
|
+
const tablesDB = new TablesDB(client);
|
|
102
|
+
|
|
103
|
+
function getMuseRuntime(): QmuseRuntimeContext {
|
|
104
|
+
return window.__MUSE__;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function getQmuseLoginUserId(): string | null {
|
|
108
|
+
const userId = window.__TERN__?.user?.clientUser?.userId;
|
|
109
|
+
return typeof userId === 'string' && userId.trim() ? userId : null;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const runtimeAccount: AppwriteAccountLike = {
|
|
113
|
+
get: () => account.get(),
|
|
114
|
+
getSession: (input) => account.getSession(input),
|
|
115
|
+
deleteSession: async (input) => {
|
|
116
|
+
await account.deleteSession(input);
|
|
117
|
+
},
|
|
118
|
+
createAnonymousSession: () => account.createAnonymousSession(),
|
|
119
|
+
createSession: (input) => account.createSession(input),
|
|
120
|
+
};
|
|
14
121
|
|
|
15
122
|
const runtime = createQmuseAppwriteRuntime({
|
|
16
123
|
client,
|
|
17
|
-
account,
|
|
124
|
+
account: runtimeAccount,
|
|
18
125
|
tablesDB,
|
|
19
|
-
getMuseRuntime
|
|
20
|
-
getQmuseLoginUserId
|
|
21
|
-
|
|
22
|
-
|
|
126
|
+
getMuseRuntime,
|
|
127
|
+
getQmuseLoginUserId,
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
export const initAppwrite = runtime.init;
|
|
131
|
+
export const getAppwriteClients = runtime.getClients;
|
|
132
|
+
export const getCurrentAppwriteUser = runtime.getCurrentUser;
|
|
133
|
+
export const refreshAppwriteSession = runtime.refreshSession;
|
|
134
|
+
export const listQmuseRows = runtime.listRows;
|
|
135
|
+
export const getQmuseRow = runtime.getRow;
|
|
136
|
+
export const createQmuseRow = runtime.createRow;
|
|
137
|
+
export const updateQmuseRow = runtime.updateRow;
|
|
138
|
+
export const deleteQmuseRow = runtime.deleteRow;
|
|
139
|
+
|
|
140
|
+
export type { Models };
|
|
141
|
+
export { ID, Permission, Query, Role };
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
每个应用只创建一个 Runtime 实例。页面、Hook 和其他业务服务统一复用该模块导出的方法。
|
|
145
|
+
|
|
146
|
+
### 3. 初始化应用
|
|
147
|
+
|
|
148
|
+
在渲染 React 根节点前完成初始化:
|
|
149
|
+
|
|
150
|
+
```tsx
|
|
151
|
+
// src/main.tsx
|
|
152
|
+
import { createRoot } from 'react-dom/client';
|
|
153
|
+
import App from './App';
|
|
154
|
+
import { initAppwrite } from './services/appwrite';
|
|
155
|
+
|
|
156
|
+
async function bootstrap() {
|
|
157
|
+
await initAppwrite();
|
|
158
|
+
createRoot(document.getElementById('root')!).render(<App />);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
bootstrap().catch((error) => {
|
|
162
|
+
console.error('Appwrite initialization failed', error);
|
|
163
|
+
});
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### 4. 在 React 组件中读取数据
|
|
167
|
+
|
|
168
|
+
```tsx
|
|
169
|
+
import { useEffect, useState } from 'react';
|
|
170
|
+
import { listQmuseRows, Query, type Models } from './services/appwrite';
|
|
171
|
+
|
|
172
|
+
type TodoRow = Models.Row & {
|
|
173
|
+
title: string;
|
|
174
|
+
completed: boolean;
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
export function TodoList() {
|
|
178
|
+
const [rows, setRows] = useState<TodoRow[]>([]);
|
|
179
|
+
|
|
180
|
+
useEffect(() => {
|
|
181
|
+
listQmuseRows<TodoRow>({
|
|
182
|
+
tableId: 'todos',
|
|
183
|
+
queries: [Query.orderDesc('$createdAt')],
|
|
184
|
+
limit: 20,
|
|
185
|
+
})
|
|
186
|
+
.then((result) => setRows(result.rows))
|
|
187
|
+
.catch((error) => console.error('Failed to load todos', error));
|
|
188
|
+
}, []);
|
|
189
|
+
|
|
190
|
+
return (
|
|
191
|
+
<ul>
|
|
192
|
+
{rows.map((row) => (
|
|
193
|
+
<li key={row.$id}>{row.title}</li>
|
|
194
|
+
))}
|
|
195
|
+
</ul>
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Taro 项目
|
|
201
|
+
|
|
202
|
+
Taro 项目通过 `createPortableAppwriteClients()` 使用同一套 Runtime API。该方式适用于 Taro H5、支付宝小程序和微信小程序。
|
|
203
|
+
|
|
204
|
+
### 1. 配置跨端环境变量
|
|
205
|
+
|
|
206
|
+
在 Taro 的 `.env.development` 和 `.env.production` 中按目标环境配置:
|
|
207
|
+
|
|
208
|
+
```dotenv
|
|
209
|
+
TARO_APP_QMUSE_APP_ID=3789326422662181
|
|
210
|
+
TARO_APP_QMUSE_RUNTIME_ENV=dev
|
|
211
|
+
TARO_APP_QMUSE_RUNTIME_DOMAIN=https://appio-pre.qmuse.cn
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
补充环境变量类型:
|
|
215
|
+
|
|
216
|
+
```ts
|
|
217
|
+
// types/global.d.ts
|
|
218
|
+
interface QMuseRuntimeConfig {
|
|
219
|
+
appId: string;
|
|
220
|
+
env: 'dev' | 'prod';
|
|
221
|
+
domain: string;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
declare namespace NodeJS {
|
|
225
|
+
interface ProcessEnv {
|
|
226
|
+
TARO_APP_QMUSE_APP_ID: string;
|
|
227
|
+
TARO_APP_QMUSE_RUNTIME_ENV: 'dev' | 'prod';
|
|
228
|
+
TARO_APP_QMUSE_RUNTIME_DOMAIN: string;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### 2. 读取固定运行时配置
|
|
234
|
+
|
|
235
|
+
```ts
|
|
236
|
+
// src/runtime/qmuse.ts
|
|
237
|
+
import type { QmuseRuntimeContext } from '@qmuse/appwrite-runtime-sdk';
|
|
238
|
+
|
|
239
|
+
const runtimeConfig: QmuseRuntimeContext = Object.freeze({
|
|
240
|
+
appId: process.env.TARO_APP_QMUSE_APP_ID,
|
|
241
|
+
env: process.env.TARO_APP_QMUSE_RUNTIME_ENV,
|
|
242
|
+
domain: process.env.TARO_APP_QMUSE_RUNTIME_DOMAIN,
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
export function getMuseRuntimeConfig(): QmuseRuntimeContext {
|
|
246
|
+
return runtimeConfig;
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
使用 `TARO_APP_*` 环境变量可以让 Taro 在 dev 和 build 命令中为 H5、支付宝和微信产物使用同一套注入方式。
|
|
251
|
+
|
|
252
|
+
### 3. 提供跨端请求与存储
|
|
253
|
+
|
|
254
|
+
H5 可以使用浏览器 `fetch`,小程序端需要将 `Taro.request` 适配为 SDK 接收的 `fetch` 接口:
|
|
255
|
+
|
|
256
|
+
```ts
|
|
257
|
+
// src/services/platform.ts
|
|
258
|
+
import Taro from '@tarojs/taro';
|
|
259
|
+
|
|
260
|
+
function normalizeHeaders(headers?: HeadersInit): Record<string, string> {
|
|
261
|
+
if (!headers) return {};
|
|
262
|
+
if (Array.isArray(headers)) return Object.fromEntries(headers);
|
|
263
|
+
if ('forEach' in headers && typeof headers.forEach === 'function') {
|
|
264
|
+
const result: Record<string, string> = {};
|
|
265
|
+
headers.forEach((value, key) => {
|
|
266
|
+
result[key] = value;
|
|
267
|
+
});
|
|
268
|
+
return result;
|
|
269
|
+
}
|
|
270
|
+
return Object.fromEntries(
|
|
271
|
+
Object.entries(headers).map(([key, value]) => [key, String(value)]),
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const taroFetch = async (
|
|
276
|
+
input: RequestInfo | URL,
|
|
277
|
+
init: RequestInit = {},
|
|
278
|
+
): Promise<Response> => {
|
|
279
|
+
const url = typeof input === 'string' ? input : input.toString();
|
|
280
|
+
const result = await Taro.request({
|
|
281
|
+
url,
|
|
282
|
+
method: (init.method || 'GET').toUpperCase() as keyof Taro.request.Method,
|
|
283
|
+
header: normalizeHeaders(init.headers),
|
|
284
|
+
data: typeof init.body === 'string' ? init.body : undefined,
|
|
285
|
+
dataType: 'text',
|
|
286
|
+
responseType: 'text',
|
|
287
|
+
});
|
|
288
|
+
const text =
|
|
289
|
+
typeof result.data === 'string'
|
|
290
|
+
? result.data
|
|
291
|
+
: JSON.stringify(result.data ?? '');
|
|
292
|
+
const responseHeaders = new Map(
|
|
293
|
+
Object.entries(result.header || {}).map(([key, value]) => [
|
|
294
|
+
key.toLowerCase(),
|
|
295
|
+
String(value),
|
|
296
|
+
]),
|
|
297
|
+
);
|
|
298
|
+
|
|
299
|
+
return {
|
|
300
|
+
ok: result.statusCode >= 200 && result.statusCode < 300,
|
|
301
|
+
status: result.statusCode,
|
|
302
|
+
headers: {
|
|
303
|
+
get: (name: string) => responseHeaders.get(name.toLowerCase()) ?? null,
|
|
304
|
+
},
|
|
305
|
+
text: async () => text,
|
|
306
|
+
} as Response;
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
export const platformFetch: typeof globalThis.fetch = ((input, init) => {
|
|
310
|
+
if (process.env.TARO_ENV === 'h5' && typeof globalThis.fetch === 'function') {
|
|
311
|
+
return globalThis.fetch(input, init);
|
|
312
|
+
}
|
|
313
|
+
return taroFetch(input, init);
|
|
314
|
+
}) as typeof globalThis.fetch;
|
|
315
|
+
|
|
316
|
+
export const platformStorage = {
|
|
317
|
+
getItem(key: string): string | null {
|
|
318
|
+
const value = Taro.getStorageSync(key);
|
|
319
|
+
return typeof value === 'string' && value ? value : null;
|
|
320
|
+
},
|
|
321
|
+
setItem(key: string, value: string): void {
|
|
322
|
+
Taro.setStorageSync(key, value);
|
|
23
323
|
},
|
|
324
|
+
removeItem(key: string): void {
|
|
325
|
+
Taro.removeStorageSync(key);
|
|
326
|
+
},
|
|
327
|
+
};
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### 4. 创建 Taro Runtime 单例
|
|
331
|
+
|
|
332
|
+
```ts
|
|
333
|
+
// src/services/appwrite.ts
|
|
334
|
+
import { ID, Permission, Query, Role } from 'appwrite';
|
|
335
|
+
import {
|
|
336
|
+
createPortableAppwriteClients,
|
|
337
|
+
createQmuseAppwriteRuntime,
|
|
338
|
+
type Models,
|
|
339
|
+
} from '@qmuse/appwrite-runtime-sdk';
|
|
340
|
+
import { getMuseRuntimeConfig } from '../runtime/qmuse';
|
|
341
|
+
import { platformFetch, platformStorage } from './platform';
|
|
342
|
+
|
|
343
|
+
function getQmuseLoginUserId(): string | null {
|
|
344
|
+
return null;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
const clients = createPortableAppwriteClients({
|
|
348
|
+
fetch: platformFetch,
|
|
349
|
+
storage: platformStorage,
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
const runtime = createQmuseAppwriteRuntime({
|
|
353
|
+
...clients,
|
|
354
|
+
getMuseRuntime: getMuseRuntimeConfig,
|
|
355
|
+
getQmuseLoginUserId,
|
|
356
|
+
fetch: platformFetch,
|
|
24
357
|
});
|
|
25
358
|
|
|
26
359
|
export const initAppwrite = runtime.init;
|
|
27
360
|
export const getAppwriteClients = runtime.getClients;
|
|
361
|
+
export const getCurrentAppwriteUser = runtime.getCurrentUser;
|
|
362
|
+
export const refreshAppwriteSession = runtime.refreshSession;
|
|
363
|
+
export const listQmuseRows = runtime.listRows;
|
|
364
|
+
export const getQmuseRow = runtime.getRow;
|
|
28
365
|
export const createQmuseRow = runtime.createRow;
|
|
29
366
|
export const updateQmuseRow = runtime.updateRow;
|
|
367
|
+
export const deleteQmuseRow = runtime.deleteRow;
|
|
368
|
+
|
|
369
|
+
export type { Models };
|
|
370
|
+
export { ID, Permission, Query, Role };
|
|
30
371
|
```
|
|
31
372
|
|
|
32
|
-
|
|
373
|
+
### 5. 在 Taro 应用启动时初始化
|
|
33
374
|
|
|
34
|
-
|
|
375
|
+
```tsx
|
|
376
|
+
// src/app.tsx
|
|
377
|
+
import type { PropsWithChildren } from 'react';
|
|
378
|
+
import { useLaunch } from '@tarojs/taro';
|
|
379
|
+
import { initAppwrite } from './services/appwrite';
|
|
35
380
|
|
|
36
|
-
|
|
381
|
+
export default function App({ children }: PropsWithChildren) {
|
|
382
|
+
useLaunch(() => {
|
|
383
|
+
initAppwrite().catch((error) => {
|
|
384
|
+
console.error('Appwrite initialization failed', error);
|
|
385
|
+
});
|
|
386
|
+
});
|
|
37
387
|
|
|
38
|
-
|
|
388
|
+
return children;
|
|
389
|
+
}
|
|
390
|
+
```
|
|
39
391
|
|
|
40
|
-
|
|
41
|
-
- `src/runtime/QmuseAppwriteRuntime.ts`:公开 API 装配与 TablesDB CRUD 编排。
|
|
42
|
-
- `src/runtime/AppwriteSessionCoordinator.ts`:Runtime 配置、Session 状态机和 401 刷新。
|
|
43
|
-
- `src/runtime/MutationAuditReporter.ts`:非阻塞 mutation 安全审计。
|
|
44
|
-
- `src/runtime/rowData.ts`:业务字段过滤与审计数据脱敏。
|
|
45
|
-
- `src/runtime/utils.ts`:HTTP 错误、fetch 延迟解析和 Promise rejection 观察。
|
|
392
|
+
业务页面和服务可以直接复用与 React 应用相同的 CRUD 方法。
|
|
46
393
|
|
|
47
|
-
|
|
394
|
+
## 数据操作
|
|
48
395
|
|
|
49
|
-
|
|
396
|
+
### 查询列表
|
|
50
397
|
|
|
51
|
-
|
|
398
|
+
```ts
|
|
399
|
+
const result = await listQmuseRows<TodoRow>({
|
|
400
|
+
tableId: 'todos',
|
|
401
|
+
queries: [Query.equal('completed', false)],
|
|
402
|
+
limit: 20,
|
|
403
|
+
cursor: previousPageLastRowId,
|
|
404
|
+
});
|
|
405
|
+
```
|
|
52
406
|
|
|
53
|
-
|
|
54
|
-
[![TNPM downloads][tnpm-downloads-image]][tnpm-url]
|
|
55
|
-

|
|
407
|
+
### 查询单行
|
|
56
408
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
409
|
+
```ts
|
|
410
|
+
const row = await getQmuseRow<TodoRow>({
|
|
411
|
+
tableId: 'todos',
|
|
412
|
+
rowId: 'todo_001',
|
|
413
|
+
});
|
|
414
|
+
```
|
|
60
415
|
|
|
61
|
-
|
|
416
|
+
### 新增
|
|
62
417
|
|
|
63
|
-
|
|
418
|
+
```ts
|
|
419
|
+
const row = await createQmuseRow<TodoRow>({
|
|
420
|
+
tableId: 'todos',
|
|
421
|
+
data: {
|
|
422
|
+
title: 'Read the SDK documentation',
|
|
423
|
+
completed: false,
|
|
424
|
+
},
|
|
425
|
+
});
|
|
426
|
+
```
|
|
64
427
|
|
|
65
|
-
|
|
66
|
-
- 使用最新版本的 [tnpm](http://web.npm.alibaba-inc.com/)
|
|
428
|
+
不传 `rowId` 时由 SDK 生成唯一 ID。
|
|
67
429
|
|
|
68
|
-
|
|
430
|
+
### 更新
|
|
69
431
|
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
|
|
432
|
+
```ts
|
|
433
|
+
await updateQmuseRow<TodoRow>({
|
|
434
|
+
tableId: 'todos',
|
|
435
|
+
rowId: 'todo_001',
|
|
436
|
+
data: { completed: true },
|
|
437
|
+
});
|
|
438
|
+
```
|
|
73
439
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
440
|
+
### 删除
|
|
441
|
+
|
|
442
|
+
```ts
|
|
443
|
+
await deleteQmuseRow({
|
|
444
|
+
tableId: 'todos',
|
|
445
|
+
rowId: 'todo_001',
|
|
446
|
+
});
|
|
78
447
|
```
|
|
79
448
|
|
|
80
|
-
##
|
|
449
|
+
## 公开 API
|
|
450
|
+
|
|
451
|
+
| API | 返回值 | 用途 |
|
|
452
|
+
| ------------------ | ------------------------------- | ---------------------------------------- |
|
|
453
|
+
| `init()` | `Promise<void>` | 初始化 Runtime 和当前用户 Session |
|
|
454
|
+
| `getClients()` | `Promise<QmuseAppwriteClients>` | 获取已配置的客户端及 `databaseId` |
|
|
455
|
+
| `getCurrentUser()` | `Promise<AppwriteUser>` | 获取当前 Appwrite 用户 |
|
|
456
|
+
| `refreshSession()` | `Promise<void>` | 主动同步 QMuse 登录态和 Appwrite Session |
|
|
457
|
+
| `listRows()` | `Promise<Models.RowList<Row>>` | 分页查询表数据 |
|
|
458
|
+
| `getRow()` | `Promise<Row>` | 查询单行数据 |
|
|
459
|
+
| `createRow()` | `Promise<Row>` | 新增数据 |
|
|
460
|
+
| `updateRow()` | `Promise<Row>` | 更新数据 |
|
|
461
|
+
| `deleteRow()` | `Promise<void>` | 删除数据 |
|
|
81
462
|
|
|
82
|
-
|
|
463
|
+
所有公开方法都是异步方法。页面和业务服务应使用 `await` 或显式处理 Promise 错误。
|
|
83
464
|
|
|
84
|
-
|
|
465
|
+
## 接入约束
|
|
85
466
|
|
|
86
|
-
|
|
467
|
+
- 每个应用只创建一个 `createQmuseAppwriteRuntime()` 实例。
|
|
468
|
+
- React 应用使用 Appwrite Web SDK 客户端;Taro 应用使用 `createPortableAppwriteClients()`。
|
|
469
|
+
- H5、支付宝小程序和微信小程序必须使用相同的 `appId`、`env` 和 `domain` 配置来源。
|
|
470
|
+
- React 应用的 `getQmuseLoginUserId()` 只返回有效的用户 ID 或 `null`;Taro 应用固定返回 `null`。
|
|
471
|
+
- 业务代码通过 Runtime 的 CRUD 方法读写数据,不直接拼接 Appwrite HTTP 接口。
|
|
472
|
+
|
|
473
|
+
## SDK 开发
|
|
87
474
|
|
|
88
475
|
```bash
|
|
89
|
-
|
|
476
|
+
tnpm install
|
|
477
|
+
npm run lint
|
|
478
|
+
npm test
|
|
479
|
+
npm run build
|
|
90
480
|
```
|
|
91
481
|
|
|
92
|
-
|
|
482
|
+
## 发布
|
|
93
483
|
|
|
94
|
-
|
|
484
|
+
先在 `package.json` 中设置未发布的语义化版本,然后执行:
|
|
95
485
|
|
|
96
486
|
```bash
|
|
97
|
-
npm
|
|
487
|
+
npm run publish:public
|
|
98
488
|
```
|
|
489
|
+
|
|
490
|
+
发布脚本默认使用 `dev` tag,也可以选择 `latest`。正式发布前应确保 lint、测试和构建全部通过。
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
export { createQmuseAppwriteRuntime } from './runtime';
|
|
2
|
-
export
|
|
2
|
+
export { createPortableAppwriteClients } from './portable';
|
|
3
|
+
export type { AppwriteAccountLike, AppwriteClientLike, AppwriteError, AppwriteRuntimeConfig, AppwriteRuntimeStorage, AppwriteSession, AppwriteTablesDBLike, AppwriteUser, BusinessRowData, CreateRowInput, DeleteRowInput, GetRowInput, ListRowsInput, Models, QmuseAppwriteClients, QmuseAppwriteRuntimeApi, QmuseAppwriteRuntimeOptions, QmuseEnvironment, QmuseRuntimeContext, PortableAppwriteClientsOptions, UpdateRowInput, } from './types';
|
package/dist/index.js
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export { createQmuseAppwriteRuntime } from "./runtime";
|
|
1
|
+
export { createQmuseAppwriteRuntime } from "./runtime";
|
|
2
|
+
export { createPortableAppwriteClients } from "./portable";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { AppwriteAccountLike, AppwriteClientLike, AppwriteTablesDBLike, PortableAppwriteClientsOptions } from './types';
|
|
2
|
+
export declare function createPortableAppwriteClients(options: PortableAppwriteClientsOptions): {
|
|
3
|
+
client: AppwriteClientLike;
|
|
4
|
+
account: AppwriteAccountLike;
|
|
5
|
+
tablesDB: AppwriteTablesDBLike;
|
|
6
|
+
};
|
package/dist/portable.js
ADDED
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
import _regeneratorRuntime from "@babel/runtime/helpers/esm/regeneratorRuntime";
|
|
2
|
+
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
|
|
3
|
+
import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
|
|
4
|
+
import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
|
|
5
|
+
import _typeof from "@babel/runtime/helpers/esm/typeof";
|
|
6
|
+
import _createClass from "@babel/runtime/helpers/esm/createClass";
|
|
7
|
+
import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
|
|
8
|
+
import _assertThisInitialized from "@babel/runtime/helpers/esm/assertThisInitialized";
|
|
9
|
+
import _inherits from "@babel/runtime/helpers/esm/inherits";
|
|
10
|
+
import _createSuper from "@babel/runtime/helpers/esm/createSuper";
|
|
11
|
+
import _wrapNativeSuper from "@babel/runtime/helpers/esm/wrapNativeSuper";
|
|
12
|
+
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
|
|
13
|
+
var PortableAppwriteError = /*#__PURE__*/function (_Error) {
|
|
14
|
+
_inherits(PortableAppwriteError, _Error);
|
|
15
|
+
var _super = _createSuper(PortableAppwriteError);
|
|
16
|
+
function PortableAppwriteError(_ref) {
|
|
17
|
+
var _this;
|
|
18
|
+
var message = _ref.message,
|
|
19
|
+
code = _ref.code,
|
|
20
|
+
type = _ref.type,
|
|
21
|
+
response = _ref.response;
|
|
22
|
+
_classCallCheck(this, PortableAppwriteError);
|
|
23
|
+
_this = _super.call(this, message);
|
|
24
|
+
_defineProperty(_assertThisInitialized(_this), "code", void 0);
|
|
25
|
+
_defineProperty(_assertThisInitialized(_this), "type", void 0);
|
|
26
|
+
_defineProperty(_assertThisInitialized(_this), "response", void 0);
|
|
27
|
+
_this.name = 'PortableAppwriteError';
|
|
28
|
+
_this.code = code;
|
|
29
|
+
_this.type = type;
|
|
30
|
+
_this.response = response;
|
|
31
|
+
return _this;
|
|
32
|
+
}
|
|
33
|
+
return _createClass(PortableAppwriteError);
|
|
34
|
+
}( /*#__PURE__*/_wrapNativeSuper(Error));
|
|
35
|
+
function isRecord(value) {
|
|
36
|
+
return Boolean(value) && _typeof(value) === 'object' && !Array.isArray(value);
|
|
37
|
+
}
|
|
38
|
+
function appendQuery(entries, key, value) {
|
|
39
|
+
if (value === undefined || value === null) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (Array.isArray(value)) {
|
|
43
|
+
value.forEach(function (item, index) {
|
|
44
|
+
return appendQuery(entries, "".concat(key, "[").concat(index, "]"), item);
|
|
45
|
+
});
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
entries.push("".concat(encodeURIComponent(key), "=").concat(encodeURIComponent(String(value))));
|
|
49
|
+
}
|
|
50
|
+
function createRequestUrl(endpoint, path, query) {
|
|
51
|
+
var url = "".concat(endpoint).concat(path);
|
|
52
|
+
var entries = [];
|
|
53
|
+
Object.entries(query || {}).forEach(function (_ref2) {
|
|
54
|
+
var _ref3 = _slicedToArray(_ref2, 2),
|
|
55
|
+
key = _ref3[0],
|
|
56
|
+
value = _ref3[1];
|
|
57
|
+
return appendQuery(entries, key, value);
|
|
58
|
+
});
|
|
59
|
+
if (entries.length === 0) {
|
|
60
|
+
return url;
|
|
61
|
+
}
|
|
62
|
+
return "".concat(url).concat(url.includes('?') ? '&' : '?').concat(entries.join('&'));
|
|
63
|
+
}
|
|
64
|
+
var PortableAppwriteClient = /*#__PURE__*/function () {
|
|
65
|
+
function PortableAppwriteClient(options) {
|
|
66
|
+
_classCallCheck(this, PortableAppwriteClient);
|
|
67
|
+
_defineProperty(this, "config", {
|
|
68
|
+
endpoint: '',
|
|
69
|
+
projectId: ''
|
|
70
|
+
});
|
|
71
|
+
_defineProperty(this, "memoryFallbackCookies", null);
|
|
72
|
+
this.options = options;
|
|
73
|
+
}
|
|
74
|
+
_createClass(PortableAppwriteClient, [{
|
|
75
|
+
key: "setEndpoint",
|
|
76
|
+
value: function setEndpoint(endpoint) {
|
|
77
|
+
if (!endpoint) {
|
|
78
|
+
throw new TypeError('Appwrite endpoint is required');
|
|
79
|
+
}
|
|
80
|
+
this.config.endpoint = endpoint.replace(/\/$/, '');
|
|
81
|
+
return this;
|
|
82
|
+
}
|
|
83
|
+
}, {
|
|
84
|
+
key: "setProject",
|
|
85
|
+
value: function setProject(projectId) {
|
|
86
|
+
if (!projectId) {
|
|
87
|
+
throw new TypeError('Appwrite projectId is required');
|
|
88
|
+
}
|
|
89
|
+
this.config.projectId = projectId;
|
|
90
|
+
this.memoryFallbackCookies = this.readStoredFallbackCookies();
|
|
91
|
+
return this;
|
|
92
|
+
}
|
|
93
|
+
}, {
|
|
94
|
+
key: "call",
|
|
95
|
+
value: function () {
|
|
96
|
+
var _call = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(_ref4) {
|
|
97
|
+
var _data;
|
|
98
|
+
var method, path, query, body, url, headers, fallbackCookies, response, responseText, data, error, nextFallbackCookies;
|
|
99
|
+
return _regeneratorRuntime().wrap(function _callee$(_context) {
|
|
100
|
+
while (1) switch (_context.prev = _context.next) {
|
|
101
|
+
case 0:
|
|
102
|
+
method = _ref4.method, path = _ref4.path, query = _ref4.query, body = _ref4.body;
|
|
103
|
+
this.assertConfigured();
|
|
104
|
+
url = createRequestUrl(this.config.endpoint, path, query);
|
|
105
|
+
headers = {
|
|
106
|
+
'X-Appwrite-Project': this.config.projectId
|
|
107
|
+
};
|
|
108
|
+
fallbackCookies = this.getFallbackCookies();
|
|
109
|
+
if (fallbackCookies) {
|
|
110
|
+
headers['X-Fallback-Cookies'] = fallbackCookies;
|
|
111
|
+
}
|
|
112
|
+
if (body) {
|
|
113
|
+
headers['Content-Type'] = 'application/json';
|
|
114
|
+
}
|
|
115
|
+
_context.next = 9;
|
|
116
|
+
return this.options.fetch(url, _objectSpread({
|
|
117
|
+
method: method,
|
|
118
|
+
credentials: 'include',
|
|
119
|
+
headers: headers
|
|
120
|
+
}, body ? {
|
|
121
|
+
body: JSON.stringify(body)
|
|
122
|
+
} : {}));
|
|
123
|
+
case 9:
|
|
124
|
+
response = _context.sent;
|
|
125
|
+
_context.next = 12;
|
|
126
|
+
return response.text();
|
|
127
|
+
case 12:
|
|
128
|
+
responseText = _context.sent;
|
|
129
|
+
data = undefined;
|
|
130
|
+
if (responseText) {
|
|
131
|
+
try {
|
|
132
|
+
data = JSON.parse(responseText);
|
|
133
|
+
} catch (_unused) {
|
|
134
|
+
data = {
|
|
135
|
+
message: responseText
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (response.ok) {
|
|
140
|
+
_context.next = 18;
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
error = isRecord(data) ? data : {};
|
|
144
|
+
throw new PortableAppwriteError({
|
|
145
|
+
message: typeof error.message === 'string' ? error.message : "Appwrite request failed: ".concat(response.status),
|
|
146
|
+
code: response.status,
|
|
147
|
+
type: typeof error.type === 'string' ? error.type : undefined,
|
|
148
|
+
response: responseText || undefined
|
|
149
|
+
});
|
|
150
|
+
case 18:
|
|
151
|
+
nextFallbackCookies = response.headers.get('X-Fallback-Cookies');
|
|
152
|
+
if (nextFallbackCookies) {
|
|
153
|
+
this.setFallbackCookies(nextFallbackCookies);
|
|
154
|
+
}
|
|
155
|
+
return _context.abrupt("return", (_data = data) !== null && _data !== void 0 ? _data : {});
|
|
156
|
+
case 21:
|
|
157
|
+
case "end":
|
|
158
|
+
return _context.stop();
|
|
159
|
+
}
|
|
160
|
+
}, _callee, this);
|
|
161
|
+
}));
|
|
162
|
+
function call(_x) {
|
|
163
|
+
return _call.apply(this, arguments);
|
|
164
|
+
}
|
|
165
|
+
return call;
|
|
166
|
+
}()
|
|
167
|
+
}, {
|
|
168
|
+
key: "clearFallbackCookies",
|
|
169
|
+
value: function clearFallbackCookies() {
|
|
170
|
+
this.memoryFallbackCookies = null;
|
|
171
|
+
var storage = this.options.storage;
|
|
172
|
+
if (storage && this.config.projectId) {
|
|
173
|
+
storage.removeItem(this.getStorageKey());
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}, {
|
|
177
|
+
key: "assertConfigured",
|
|
178
|
+
value: function assertConfigured() {
|
|
179
|
+
if (!this.config.endpoint || !this.config.projectId) {
|
|
180
|
+
throw new Error('Portable Appwrite client is not initialized');
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}, {
|
|
184
|
+
key: "getStorageKey",
|
|
185
|
+
value: function getStorageKey() {
|
|
186
|
+
var prefix = this.options.storageKeyPrefix || 'qmuse:appwrite:session';
|
|
187
|
+
return "".concat(prefix, ":").concat(this.config.projectId);
|
|
188
|
+
}
|
|
189
|
+
}, {
|
|
190
|
+
key: "readStoredFallbackCookies",
|
|
191
|
+
value: function readStoredFallbackCookies() {
|
|
192
|
+
if (!this.options.storage || !this.config.projectId) {
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
var stored = this.options.storage.getItem(this.getStorageKey());
|
|
196
|
+
return typeof stored === 'string' && stored ? stored : null;
|
|
197
|
+
}
|
|
198
|
+
}, {
|
|
199
|
+
key: "getFallbackCookies",
|
|
200
|
+
value: function getFallbackCookies() {
|
|
201
|
+
return this.memoryFallbackCookies || this.readStoredFallbackCookies();
|
|
202
|
+
}
|
|
203
|
+
}, {
|
|
204
|
+
key: "setFallbackCookies",
|
|
205
|
+
value: function setFallbackCookies(value) {
|
|
206
|
+
var _this$options$storage;
|
|
207
|
+
this.memoryFallbackCookies = value;
|
|
208
|
+
(_this$options$storage = this.options.storage) === null || _this$options$storage === void 0 || _this$options$storage.setItem(this.getStorageKey(), value);
|
|
209
|
+
}
|
|
210
|
+
}]);
|
|
211
|
+
return PortableAppwriteClient;
|
|
212
|
+
}();
|
|
213
|
+
var PortableAccount = /*#__PURE__*/function () {
|
|
214
|
+
function PortableAccount(client) {
|
|
215
|
+
_classCallCheck(this, PortableAccount);
|
|
216
|
+
this.client = client;
|
|
217
|
+
}
|
|
218
|
+
_createClass(PortableAccount, [{
|
|
219
|
+
key: "get",
|
|
220
|
+
value: function get() {
|
|
221
|
+
return this.client.call({
|
|
222
|
+
method: 'GET',
|
|
223
|
+
path: '/account'
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
}, {
|
|
227
|
+
key: "getSession",
|
|
228
|
+
value: function getSession(_ref5) {
|
|
229
|
+
var sessionId = _ref5.sessionId;
|
|
230
|
+
return this.client.call({
|
|
231
|
+
method: 'GET',
|
|
232
|
+
path: "/account/sessions/".concat(sessionId)
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
}, {
|
|
236
|
+
key: "deleteSession",
|
|
237
|
+
value: function () {
|
|
238
|
+
var _deleteSession = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2(_ref6) {
|
|
239
|
+
var sessionId;
|
|
240
|
+
return _regeneratorRuntime().wrap(function _callee2$(_context2) {
|
|
241
|
+
while (1) switch (_context2.prev = _context2.next) {
|
|
242
|
+
case 0:
|
|
243
|
+
sessionId = _ref6.sessionId;
|
|
244
|
+
_context2.prev = 1;
|
|
245
|
+
_context2.next = 4;
|
|
246
|
+
return this.client.call({
|
|
247
|
+
method: 'DELETE',
|
|
248
|
+
path: "/account/sessions/".concat(sessionId)
|
|
249
|
+
});
|
|
250
|
+
case 4:
|
|
251
|
+
_context2.prev = 4;
|
|
252
|
+
this.client.clearFallbackCookies();
|
|
253
|
+
return _context2.finish(4);
|
|
254
|
+
case 7:
|
|
255
|
+
case "end":
|
|
256
|
+
return _context2.stop();
|
|
257
|
+
}
|
|
258
|
+
}, _callee2, this, [[1,, 4, 7]]);
|
|
259
|
+
}));
|
|
260
|
+
function deleteSession(_x2) {
|
|
261
|
+
return _deleteSession.apply(this, arguments);
|
|
262
|
+
}
|
|
263
|
+
return deleteSession;
|
|
264
|
+
}()
|
|
265
|
+
}, {
|
|
266
|
+
key: "createAnonymousSession",
|
|
267
|
+
value: function createAnonymousSession() {
|
|
268
|
+
return this.client.call({
|
|
269
|
+
method: 'POST',
|
|
270
|
+
path: '/account/sessions/anonymous'
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
}, {
|
|
274
|
+
key: "createSession",
|
|
275
|
+
value: function createSession(_ref7) {
|
|
276
|
+
var userId = _ref7.userId,
|
|
277
|
+
secret = _ref7.secret;
|
|
278
|
+
return this.client.call({
|
|
279
|
+
method: 'POST',
|
|
280
|
+
path: '/account/sessions/token',
|
|
281
|
+
body: {
|
|
282
|
+
userId: userId,
|
|
283
|
+
secret: secret
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
}]);
|
|
288
|
+
return PortableAccount;
|
|
289
|
+
}();
|
|
290
|
+
var PortableTablesDB = /*#__PURE__*/function () {
|
|
291
|
+
function PortableTablesDB(client) {
|
|
292
|
+
_classCallCheck(this, PortableTablesDB);
|
|
293
|
+
this.client = client;
|
|
294
|
+
}
|
|
295
|
+
_createClass(PortableTablesDB, [{
|
|
296
|
+
key: "listRows",
|
|
297
|
+
value: function listRows(_ref8) {
|
|
298
|
+
var databaseId = _ref8.databaseId,
|
|
299
|
+
tableId = _ref8.tableId,
|
|
300
|
+
queries = _ref8.queries;
|
|
301
|
+
return this.client.call({
|
|
302
|
+
method: 'GET',
|
|
303
|
+
path: this.rowsPath(databaseId, tableId),
|
|
304
|
+
query: {
|
|
305
|
+
queries: queries
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
}, {
|
|
310
|
+
key: "getRow",
|
|
311
|
+
value: function getRow(_ref9) {
|
|
312
|
+
var databaseId = _ref9.databaseId,
|
|
313
|
+
tableId = _ref9.tableId,
|
|
314
|
+
rowId = _ref9.rowId;
|
|
315
|
+
return this.client.call({
|
|
316
|
+
method: 'GET',
|
|
317
|
+
path: "".concat(this.rowsPath(databaseId, tableId), "/").concat(encodeURIComponent(rowId))
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
}, {
|
|
321
|
+
key: "createRow",
|
|
322
|
+
value: function createRow(_ref10) {
|
|
323
|
+
var databaseId = _ref10.databaseId,
|
|
324
|
+
tableId = _ref10.tableId,
|
|
325
|
+
rowId = _ref10.rowId,
|
|
326
|
+
data = _ref10.data,
|
|
327
|
+
permissions = _ref10.permissions;
|
|
328
|
+
return this.client.call({
|
|
329
|
+
method: 'POST',
|
|
330
|
+
path: this.rowsPath(databaseId, tableId),
|
|
331
|
+
body: {
|
|
332
|
+
rowId: rowId,
|
|
333
|
+
data: data,
|
|
334
|
+
permissions: permissions
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
}, {
|
|
339
|
+
key: "updateRow",
|
|
340
|
+
value: function updateRow(_ref11) {
|
|
341
|
+
var databaseId = _ref11.databaseId,
|
|
342
|
+
tableId = _ref11.tableId,
|
|
343
|
+
rowId = _ref11.rowId,
|
|
344
|
+
data = _ref11.data;
|
|
345
|
+
return this.client.call({
|
|
346
|
+
method: 'PATCH',
|
|
347
|
+
path: "".concat(this.rowsPath(databaseId, tableId), "/").concat(encodeURIComponent(rowId)),
|
|
348
|
+
body: {
|
|
349
|
+
data: data
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
}, {
|
|
354
|
+
key: "deleteRow",
|
|
355
|
+
value: function deleteRow(_ref12) {
|
|
356
|
+
var databaseId = _ref12.databaseId,
|
|
357
|
+
tableId = _ref12.tableId,
|
|
358
|
+
rowId = _ref12.rowId;
|
|
359
|
+
return this.client.call({
|
|
360
|
+
method: 'DELETE',
|
|
361
|
+
path: "".concat(this.rowsPath(databaseId, tableId), "/").concat(encodeURIComponent(rowId))
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
}, {
|
|
365
|
+
key: "rowsPath",
|
|
366
|
+
value: function rowsPath(databaseId, tableId) {
|
|
367
|
+
return "/tablesdb/".concat(encodeURIComponent(databaseId), "/tables/").concat(encodeURIComponent(tableId), "/rows");
|
|
368
|
+
}
|
|
369
|
+
}]);
|
|
370
|
+
return PortableTablesDB;
|
|
371
|
+
}();
|
|
372
|
+
export function createPortableAppwriteClients(options) {
|
|
373
|
+
var client = new PortableAppwriteClient(options);
|
|
374
|
+
return {
|
|
375
|
+
client: client,
|
|
376
|
+
account: new PortableAccount(client),
|
|
377
|
+
tablesDB: new PortableTablesDB(client)
|
|
378
|
+
};
|
|
379
|
+
}
|
|
@@ -5,7 +5,7 @@ import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
|
|
|
5
5
|
import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
|
|
6
6
|
import _createClass from "@babel/runtime/helpers/esm/createClass";
|
|
7
7
|
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
|
|
8
|
-
import { createResponseError, getErrorCode, isRecord, readResponsePayload } from "./utils";
|
|
8
|
+
import { createResponseError, getErrorCode, isRecord, readResponsePayload, resolveRuntimeUrl } from "./utils";
|
|
9
9
|
export var AppwriteSessionCoordinator = /*#__PURE__*/function () {
|
|
10
10
|
function AppwriteSessionCoordinator(options, request) {
|
|
11
11
|
_classCallCheck(this, AppwriteSessionCoordinator);
|
|
@@ -209,7 +209,7 @@ export var AppwriteSessionCoordinator = /*#__PURE__*/function () {
|
|
|
209
209
|
case 0:
|
|
210
210
|
runtime = this.getMuseRuntime();
|
|
211
211
|
_context6.next = 3;
|
|
212
|
-
return this.request(
|
|
212
|
+
return this.request(resolveRuntimeUrl('/runtime/appwrite/config', runtime.domain), {
|
|
213
213
|
method: 'POST',
|
|
214
214
|
credentials: 'include',
|
|
215
215
|
headers: {
|
|
@@ -380,31 +380,24 @@ export var AppwriteSessionCoordinator = /*#__PURE__*/function () {
|
|
|
380
380
|
while (1) switch (_context10.prev = _context10.next) {
|
|
381
381
|
case 0:
|
|
382
382
|
forceReplace = _args10.length > 0 && _args10[0] !== undefined ? _args10[0] : false;
|
|
383
|
-
if (this.state.currentUser) {
|
|
384
|
-
_context10.next = 4;
|
|
385
|
-
break;
|
|
386
|
-
}
|
|
387
|
-
_context10.next = 4;
|
|
388
|
-
return this.tryCacheCurrentSession();
|
|
389
|
-
case 4:
|
|
390
383
|
if (!(!forceReplace && this.state.currentUser && this.state.currentSessionProvider === 'anonymous')) {
|
|
391
|
-
_context10.next =
|
|
384
|
+
_context10.next = 4;
|
|
392
385
|
break;
|
|
393
386
|
}
|
|
394
387
|
this.state.confirmedQmuseUserId = null;
|
|
395
388
|
return _context10.abrupt("return");
|
|
396
|
-
case
|
|
397
|
-
_context10.next =
|
|
389
|
+
case 4:
|
|
390
|
+
_context10.next = 6;
|
|
398
391
|
return this.deleteCurrentSession();
|
|
399
|
-
case
|
|
400
|
-
_context10.next =
|
|
392
|
+
case 6:
|
|
393
|
+
_context10.next = 8;
|
|
401
394
|
return this.options.account.createAnonymousSession();
|
|
402
|
-
case
|
|
403
|
-
_context10.next =
|
|
395
|
+
case 8:
|
|
396
|
+
_context10.next = 10;
|
|
404
397
|
return this.cacheCurrentSession();
|
|
405
|
-
case
|
|
398
|
+
case 10:
|
|
406
399
|
this.state.confirmedQmuseUserId = null;
|
|
407
|
-
case
|
|
400
|
+
case 11:
|
|
408
401
|
case "end":
|
|
409
402
|
return _context10.stop();
|
|
410
403
|
}
|
|
@@ -426,7 +419,7 @@ export var AppwriteSessionCoordinator = /*#__PURE__*/function () {
|
|
|
426
419
|
runtime = this.getMuseRuntime();
|
|
427
420
|
config = this.requireRuntimeConfig();
|
|
428
421
|
_context11.next = 4;
|
|
429
|
-
return this.request(
|
|
422
|
+
return this.request(resolveRuntimeUrl(config.authTokenEndpoint, runtime.domain), {
|
|
430
423
|
method: 'POST',
|
|
431
424
|
credentials: 'include',
|
|
432
425
|
headers: {
|
|
@@ -434,7 +427,6 @@ export var AppwriteSessionCoordinator = /*#__PURE__*/function () {
|
|
|
434
427
|
},
|
|
435
428
|
body: JSON.stringify({
|
|
436
429
|
appId: runtime.appId,
|
|
437
|
-
appVersionId: runtime.appVersionId,
|
|
438
430
|
env: runtime.env,
|
|
439
431
|
projectId: config.projectId
|
|
440
432
|
})
|
|
@@ -493,34 +485,27 @@ export var AppwriteSessionCoordinator = /*#__PURE__*/function () {
|
|
|
493
485
|
while (1) switch (_context12.prev = _context12.next) {
|
|
494
486
|
case 0:
|
|
495
487
|
qmuseUserId = _ref2.qmuseUserId, userId = _ref2.userId, secret = _ref2.secret, _ref2$forceReplace = _ref2.forceReplace, forceReplace = _ref2$forceReplace === void 0 ? false : _ref2$forceReplace;
|
|
496
|
-
if (this.state.currentUser) {
|
|
497
|
-
_context12.next = 4;
|
|
498
|
-
break;
|
|
499
|
-
}
|
|
500
|
-
_context12.next = 4;
|
|
501
|
-
return this.tryCacheCurrentSession();
|
|
502
|
-
case 4:
|
|
503
488
|
if (!(!forceReplace && this.state.currentUser && this.state.currentSessionProvider !== 'anonymous' && this.state.currentUser.$id === userId)) {
|
|
504
|
-
_context12.next =
|
|
489
|
+
_context12.next = 4;
|
|
505
490
|
break;
|
|
506
491
|
}
|
|
507
492
|
this.state.confirmedQmuseUserId = qmuseUserId;
|
|
508
493
|
return _context12.abrupt("return");
|
|
509
|
-
case
|
|
510
|
-
_context12.next =
|
|
494
|
+
case 4:
|
|
495
|
+
_context12.next = 6;
|
|
511
496
|
return this.deleteCurrentSession();
|
|
512
|
-
case
|
|
513
|
-
_context12.next =
|
|
497
|
+
case 6:
|
|
498
|
+
_context12.next = 8;
|
|
514
499
|
return this.options.account.createSession({
|
|
515
500
|
userId: userId,
|
|
516
501
|
secret: secret
|
|
517
502
|
});
|
|
518
|
-
case
|
|
519
|
-
_context12.next =
|
|
503
|
+
case 8:
|
|
504
|
+
_context12.next = 10;
|
|
520
505
|
return this.cacheCurrentSession();
|
|
521
|
-
case
|
|
506
|
+
case 10:
|
|
522
507
|
this.state.confirmedQmuseUserId = qmuseUserId;
|
|
523
|
-
case
|
|
508
|
+
case 11:
|
|
524
509
|
case "end":
|
|
525
510
|
return _context12.stop();
|
|
526
511
|
}
|
|
@@ -3,7 +3,7 @@ import _regeneratorRuntime from "@babel/runtime/helpers/esm/regeneratorRuntime";
|
|
|
3
3
|
import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
|
|
4
4
|
import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
|
|
5
5
|
import _createClass from "@babel/runtime/helpers/esm/createClass";
|
|
6
|
-
import { getErrorCode } from "./utils";
|
|
6
|
+
import { getErrorCode, resolveRuntimeUrl } from "./utils";
|
|
7
7
|
export var MutationAuditReporter = /*#__PURE__*/function () {
|
|
8
8
|
function MutationAuditReporter(request, getMuseRuntime) {
|
|
9
9
|
_classCallCheck(this, MutationAuditReporter);
|
|
@@ -73,7 +73,7 @@ export var MutationAuditReporter = /*#__PURE__*/function () {
|
|
|
73
73
|
var runtime = this.getMuseRuntime();
|
|
74
74
|
globalThis.setTimeout(function () {
|
|
75
75
|
try {
|
|
76
|
-
void Promise.resolve(_this.request(
|
|
76
|
+
void Promise.resolve(_this.request(resolveRuntimeUrl('/api/runtime/appwrite/mutation-events', runtime.domain), {
|
|
77
77
|
method: 'POST',
|
|
78
78
|
credentials: 'include',
|
|
79
79
|
keepalive: true,
|
package/dist/runtime/utils.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export declare function createResponseError({ payload, status, fallbackMessage,
|
|
|
8
8
|
}): Error;
|
|
9
9
|
export declare function readResponsePayload(response: Response): Promise<Record<string, unknown> | null>;
|
|
10
10
|
export declare function createFetchRequest(configuredFetch?: typeof globalThis.fetch): typeof globalThis.fetch;
|
|
11
|
+
export declare function resolveRuntimeUrl(pathOrUrl: string, domain: string): string;
|
|
11
12
|
type PublicPromiseOperation = (...args: never[]) => Promise<unknown>;
|
|
12
13
|
export declare function observePublicPromise<TOperation extends PublicPromiseOperation>(operation: TOperation): TOperation;
|
|
13
14
|
export {};
|
package/dist/runtime/utils.js
CHANGED
|
@@ -8,8 +8,19 @@ export function getErrorCode(error) {
|
|
|
8
8
|
if (!isRecord(error)) {
|
|
9
9
|
return null;
|
|
10
10
|
}
|
|
11
|
-
var
|
|
12
|
-
|
|
11
|
+
var response = isRecord(error.response) ? error.response : null;
|
|
12
|
+
var candidates = [error.code, error.status, error.statusCode, response === null || response === void 0 ? void 0 : response.status, response === null || response === void 0 ? void 0 : response.statusCode];
|
|
13
|
+
for (var _i = 0, _candidates = candidates; _i < _candidates.length; _i++) {
|
|
14
|
+
var candidate = _candidates[_i];
|
|
15
|
+
if (candidate === undefined || candidate === null || candidate === '') {
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
var code = Number(candidate);
|
|
19
|
+
if (Number.isFinite(code)) {
|
|
20
|
+
return code;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
13
24
|
}
|
|
14
25
|
export function createResponseError(_ref) {
|
|
15
26
|
var _payload$code, _payload$type;
|
|
@@ -57,6 +68,14 @@ export function createFetchRequest(configuredFetch) {
|
|
|
57
68
|
return fetchImplementation(input, init);
|
|
58
69
|
};
|
|
59
70
|
}
|
|
71
|
+
export function resolveRuntimeUrl(pathOrUrl, domain) {
|
|
72
|
+
if (/^https?:\/\//i.test(pathOrUrl)) {
|
|
73
|
+
return pathOrUrl;
|
|
74
|
+
}
|
|
75
|
+
var origin = domain.replace(/\/+$/, '');
|
|
76
|
+
var path = pathOrUrl.replace(/^\/+/, '');
|
|
77
|
+
return "".concat(origin, "/").concat(path);
|
|
78
|
+
}
|
|
60
79
|
export function observePublicPromise(operation) {
|
|
61
80
|
return function () {
|
|
62
81
|
var promise = operation.apply(void 0, arguments);
|
package/dist/types.d.ts
CHANGED
|
@@ -3,7 +3,6 @@ export type { Models } from 'appwrite';
|
|
|
3
3
|
export type QmuseEnvironment = 'dev' | 'prod';
|
|
4
4
|
export interface QmuseRuntimeContext {
|
|
5
5
|
appId: string;
|
|
6
|
-
appVersionId: string;
|
|
7
6
|
env: QmuseEnvironment;
|
|
8
7
|
domain: string;
|
|
9
8
|
}
|
|
@@ -27,6 +26,16 @@ export interface AppwriteClientLike {
|
|
|
27
26
|
setEndpoint(endpoint: string): AppwriteClientLike;
|
|
28
27
|
setProject(projectId: string): AppwriteClientLike;
|
|
29
28
|
}
|
|
29
|
+
export interface AppwriteRuntimeStorage {
|
|
30
|
+
getItem(key: string): string | null | undefined;
|
|
31
|
+
setItem(key: string, value: string): void;
|
|
32
|
+
removeItem(key: string): void;
|
|
33
|
+
}
|
|
34
|
+
export interface PortableAppwriteClientsOptions {
|
|
35
|
+
fetch: typeof globalThis.fetch;
|
|
36
|
+
storage?: AppwriteRuntimeStorage;
|
|
37
|
+
storageKeyPrefix?: string;
|
|
38
|
+
}
|
|
30
39
|
export interface AppwriteAccountLike {
|
|
31
40
|
get(): Promise<AppwriteUser>;
|
|
32
41
|
getSession(input: {
|