@qmuse/appwrite-runtime-sdk 1.0.4 → 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 CHANGED
@@ -1,98 +1,490 @@
1
- # QMuse Appwrite Runtime SDK
1
+ # @qmuse/appwrite-runtime-sdk
2
2
 
3
- 浏览器端 QMuse Appwrite Runtime SDK。应用仍在 `src/services/appwrite.ts` 创建唯一的 Appwrite `Client`、`Account` 和 `TablesDB`,本包负责 Runtime 配置、Session 协调、单次 401 刷新和带审计字段保护的 TablesDB CRUD。
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
- import { Account, Client, TablesDB } from 'appwrite';
9
- import { createQmuseAppwriteRuntime } from '@alipay/appwrite-runtime-sdk';
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
- export const client = new Client();
12
- export const account = new Account(client);
13
- export const tablesDB = new TablesDB(client);
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: () => window.__MUSE__,
20
- getQmuseLoginUserId: () => {
21
- const userId = window.__TERN__?.user?.clientUser?.userId;
22
- return typeof userId === 'string' && userId.trim() ? userId : null;
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
- `createQmuseAppwriteRuntime()` 返回的实例应在 `src/services/appwrite.ts` 中作为模块级单例复用。实例创建后会立即异步初始化;`initAppwrite()` 返回同一个共享 Promise,`getAppwriteClients()` 和所有 CRUD 也会等待该初始化。SDK 会在内部观察每个公开方法返回的 Promise,因此忽略后台初始化或数据调用不会产生影响应用运行的全局 `unhandledrejection`;显式等待仍会收到同一个 Promise 的原始错误,初始化失败后下一次调用可以重试。
373
+ ### 5. Taro 应用启动时初始化
33
374
 
34
- 工厂创建阶段不因缺少 `fetch` 或 Runtime 配置异常同步抛错;这类问题会进入共享初始化 Promise。异步审计链路中的 Runtime 读取、URL 构造和请求错误也不会改变 CRUD 结果。
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
- `getCurrentAppwriteUser()` 同样是异步方法,使用时需要 `await`;它会先等待共享初始化,不会在调用阶段同步抛错。
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
- - `src/runtime.ts`:稳定的工厂入口。
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
- 不要在页面、hook 或业务服务中直接创建 Appwrite SDK 实例,或绕过 `createRow` / `updateRow` 写入审计字段。
394
+ ## 数据操作
48
395
 
49
- 新增、更新和删除会由 SDK 内置地异步上报最小审计事件;上报不阻塞 CRUD,也不向业务代码暴露 hook、开关或 API Key。SDK 不上传业务 data、custom-token 或 Session。项目内置的 Appwrite 事件云函数仍负责成功 mutation 的可靠服务端审计与重试;浏览器侧上报只用于补充安全信号。
396
+ ### 查询列表
50
397
 
51
- ## Badges
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
- [![TNPM version][tnpm-image]][tnpm-url]
54
- [![TNPM downloads][tnpm-downloads-image]][tnpm-url]
55
- ![install-node 20](https://hitu.alipay.com/badge/tnpm?title=install-node&value=20)
407
+ ### 查询单行
56
408
 
57
- [tnpm-image]: https://npm.alibaba-inc.com/badge/v/@alipay/appwrite-runtime-sdk.svg
58
- [tnpm-url]: https://npm.alibaba-inc.com/package/@alipay/appwrite-runtime-sdk
59
- [tnpm-downloads-image]: https://npm.alibaba-inc.com/badge/d/@alipay/appwrite-runtime-sdk.svg
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
- - 安装 [nodejs](https://nodejs.org/en/)
66
- - 使用最新版本的 [tnpm](http://web.npm.alibaba-inc.com/)
428
+ 不传 `rowId` 时由 SDK 生成唯一 ID。
67
429
 
68
- ## 开发
430
+ ### 更新
69
431
 
70
- ```bash
71
- # 安装依赖
72
- $ tnpm install
432
+ ```ts
433
+ await updateQmuseRow<TodoRow>({
434
+ tableId: 'todos',
435
+ rowId: 'todo_001',
436
+ data: { completed: true },
437
+ });
438
+ ```
73
439
 
74
- # 构建与检查
75
- $ npm run build
76
- $ npm run lint
77
- $ npm test
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
- SDK 不发布为海兔资产;构建、测试和公网 npm 发布均使用独立工具链。
463
+ 所有公开方法都是异步方法。页面和业务服务应使用 `await` 或显式处理 Promise 错误。
83
464
 
84
- ### 公网 `@qmuse` 包
465
+ ## 接入约束
85
466
 
86
- 先在 `package.json` 设定未发布的正式语义化版本,再执行:
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
- npm run publish:public
476
+ tnpm install
477
+ npm run lint
478
+ npm test
479
+ npm run build
90
480
  ```
91
481
 
92
- 脚本会先询问发布 tag,直接回车默认发布到 `dev`,也可以输入 `latest`。它会验证 npmjs 登录态、检查版本是否已存在,并运行 CI 与构建。确认后,它只在发布期间把包名临时改为 `@qmuse/appwrite-runtime-sdk`,退出时恢复本地 `package.json`。
482
+ ## 发布
93
483
 
94
- 首次正式发布建议先选择 `dev` 验证;确认无误后,可直接再次执行脚本并选择 `latest`,或移动 `latest` tag:
484
+ 先在 `package.json` 中设置未发布的语义化版本,然后执行:
95
485
 
96
486
  ```bash
97
- npm dist-tag add @qmuse/appwrite-runtime-sdk@<version> latest --registry https://registry.npmjs.org/
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 type { AppwriteAccountLike, AppwriteClientLike, AppwriteError, AppwriteRuntimeConfig, AppwriteSession, AppwriteTablesDBLike, AppwriteUser, BusinessRowData, CreateRowInput, DeleteRowInput, GetRowInput, ListRowsInput, Models, QmuseAppwriteClients, QmuseAppwriteRuntimeApi, QmuseAppwriteRuntimeOptions, QmuseEnvironment, QmuseRuntimeContext, UpdateRowInput, } from './types';
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
+ };
@@ -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(new URL('/runtime/appwrite/config', runtime.domain).toString(), {
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 = 7;
384
+ _context10.next = 4;
392
385
  break;
393
386
  }
394
387
  this.state.confirmedQmuseUserId = null;
395
388
  return _context10.abrupt("return");
396
- case 7:
397
- _context10.next = 9;
389
+ case 4:
390
+ _context10.next = 6;
398
391
  return this.deleteCurrentSession();
399
- case 9:
400
- _context10.next = 11;
392
+ case 6:
393
+ _context10.next = 8;
401
394
  return this.options.account.createAnonymousSession();
402
- case 11:
403
- _context10.next = 13;
395
+ case 8:
396
+ _context10.next = 10;
404
397
  return this.cacheCurrentSession();
405
- case 13:
398
+ case 10:
406
399
  this.state.confirmedQmuseUserId = null;
407
- case 14:
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(new URL(config.authTokenEndpoint, runtime.domain).toString(), {
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 = 7;
489
+ _context12.next = 4;
505
490
  break;
506
491
  }
507
492
  this.state.confirmedQmuseUserId = qmuseUserId;
508
493
  return _context12.abrupt("return");
509
- case 7:
510
- _context12.next = 9;
494
+ case 4:
495
+ _context12.next = 6;
511
496
  return this.deleteCurrentSession();
512
- case 9:
513
- _context12.next = 11;
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 11:
519
- _context12.next = 13;
503
+ case 8:
504
+ _context12.next = 10;
520
505
  return this.cacheCurrentSession();
521
- case 13:
506
+ case 10:
522
507
  this.state.confirmedQmuseUserId = qmuseUserId;
523
- case 14:
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(new URL('/api/runtime/appwrite/mutation-events', runtime.domain).toString(), {
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,
@@ -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 {};
@@ -8,8 +8,19 @@ export function getErrorCode(error) {
8
8
  if (!isRecord(error)) {
9
9
  return null;
10
10
  }
11
- var code = Number(error.code);
12
- return Number.isFinite(code) ? code : null;
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: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qmuse/appwrite-runtime-sdk",
3
- "version": "1.0.4",
3
+ "version": "1.0.5-dev.1",
4
4
  "description": "QMuse Appwrite browser runtime SDK",
5
5
  "repository": {
6
6
  "type": "git",