@qmuse/appwrite-runtime-sdk 1.0.5-dev.2 → 1.0.5-dev.3

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
@@ -201,55 +201,40 @@ export function TodoList() {
201
201
 
202
202
  Taro 项目通过 `createQmuseAppwriteRuntime()` 使用同一套 Runtime API,SDK 会在内部创建跨端客户端。该方式适用于 Taro H5、支付宝小程序和微信小程序。
203
203
 
204
+ Taro 的跨端客户端模式必须从构建环境传入 `appwriteConfig`,SDK 不会请求 `/runtime/appwrite/config`。React Web 应用原有的动态配置流程不受影响。
205
+
204
206
  ### 1. 配置跨端环境变量
205
207
 
206
208
  在 Taro 的 `.env.development` 和 `.env.production` 中按目标环境配置:
207
209
 
208
210
  ```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
211
+ QMUSE_APP_ID=3789326422662181
212
+ QMUSE_RUNTIME_ENV=dev
213
+ QMUSE_RUNTIME_DOMAIN=https://appio-pre.qmuse.cn
214
+ QMUSE_APPWRITE_ENDPOINT=https://appbase-qmuse.oceanbase.com/v1
215
+ QMUSE_APPWRITE_PROJECT_ID=6a8e99ba000a9dc3fe53
216
+ QMUSE_APPWRITE_DATABASE_ID=qmuse-app-db
212
217
  ```
213
218
 
214
219
  补充环境变量类型:
215
220
 
216
221
  ```ts
217
222
  // types/global.d.ts
218
- interface QMuseRuntimeConfig {
219
- appId: string;
220
- env: 'dev' | 'prod';
221
- domain: string;
222
- }
223
-
224
223
  declare namespace NodeJS {
225
224
  interface ProcessEnv {
226
- TARO_APP_QMUSE_APP_ID: string;
227
- TARO_APP_QMUSE_RUNTIME_ENV: 'dev' | 'prod';
228
- TARO_APP_QMUSE_RUNTIME_DOMAIN: string;
225
+ QMUSE_APP_ID: string;
226
+ QMUSE_RUNTIME_ENV: 'dev' | 'prod';
227
+ QMUSE_RUNTIME_DOMAIN: string;
228
+ QMUSE_APPWRITE_ENDPOINT: string;
229
+ QMUSE_APPWRITE_PROJECT_ID: string;
230
+ QMUSE_APPWRITE_DATABASE_ID: string;
229
231
  }
230
232
  }
231
233
  ```
232
234
 
233
- ### 2. 读取固定运行时配置
235
+ 所有 Taro dev/build 命令都需要增加 `--env-prefix QMUSE_`。上述配置会编译进客户端产物,只能存放公开连接信息,禁止写入 Appwrite API Key、Custom Token secret 或用户 Session。
234
236
 
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. 提供跨端请求与存储
237
+ ### 2. 提供跨端请求与存储
253
238
 
254
239
  H5 可以使用浏览器 `fetch`,小程序端需要将 `Taro.request` 适配为 SDK 接收的 `fetch` 接口:
255
240
 
@@ -327,24 +312,40 @@ export const platformStorage = {
327
312
  };
328
313
  ```
329
314
 
330
- ### 4. 创建 Taro Runtime 单例
315
+ ### 3. 创建 Taro Runtime 单例
331
316
 
332
317
  ```ts
333
318
  // src/services/appwrite.ts
334
319
  import { ID, Permission, Query, Role } from 'appwrite';
335
320
  import {
336
321
  createQmuseAppwriteRuntime,
322
+ type AppwriteRuntimeConfig,
337
323
  type Models,
324
+ type QmuseRuntimeContext,
338
325
  } from '@qmuse/appwrite-runtime-sdk';
339
- import { getMuseRuntimeConfig } from '../runtime/qmuse';
340
326
  import { platformFetch, platformStorage } from './platform';
341
327
 
328
+ function getMuseRuntime(): QmuseRuntimeContext {
329
+ return {
330
+ appId: process.env.QMUSE_APP_ID,
331
+ env: process.env.QMUSE_RUNTIME_ENV,
332
+ domain: process.env.QMUSE_RUNTIME_DOMAIN,
333
+ };
334
+ }
335
+
336
+ const appwriteConfig: AppwriteRuntimeConfig = {
337
+ endpoint: process.env.QMUSE_APPWRITE_ENDPOINT,
338
+ projectId: process.env.QMUSE_APPWRITE_PROJECT_ID,
339
+ databaseId: process.env.QMUSE_APPWRITE_DATABASE_ID,
340
+ };
341
+
342
342
  function getQmuseLoginUserId(): string | null {
343
343
  return null;
344
344
  }
345
345
 
346
346
  const runtime = createQmuseAppwriteRuntime({
347
- getMuseRuntime: getMuseRuntimeConfig,
347
+ appwriteConfig,
348
+ getMuseRuntime,
348
349
  getQmuseLoginUserId,
349
350
  fetch: platformFetch,
350
351
  storage: platformStorage,
@@ -364,7 +365,7 @@ export type { Models };
364
365
  export { ID, Permission, Query, Role };
365
366
  ```
366
367
 
367
- ### 5. 在 Taro 应用启动时初始化
368
+ ### 4. 在 Taro 应用启动时初始化
368
369
 
369
370
  ```tsx
370
371
  // src/app.tsx
@@ -459,7 +460,7 @@ await deleteQmuseRow({
459
460
  ## 接入约束
460
461
 
461
462
  - 每个应用只创建一个 `createQmuseAppwriteRuntime()` 实例。
462
- - React 应用向 `createQmuseAppwriteRuntime()` 传入 Appwrite Web SDK 客户端;Taro 应用传入跨端 `fetch` `storage`。
463
+ - React 应用向 `createQmuseAppwriteRuntime()` 传入 Appwrite Web SDK 客户端;Taro 应用传入跨端 `fetch`、`storage` 和构建期 `appwriteConfig`。
463
464
  - H5、支付宝小程序和微信小程序必须使用相同的 `appId`、`env` 和 `domain` 配置来源。
464
465
  - React 应用的 `getQmuseLoginUserId()` 只返回有效的用户 ID 或 `null`;Taro 应用固定返回 `null`。
465
466
  - 业务代码通过 Runtime 的 CRUD 方法读写数据,不直接拼接 Appwrite HTTP 接口。
@@ -16,6 +16,7 @@ export declare class AppwriteSessionCoordinator {
16
16
  private getMuseRuntime;
17
17
  private requireRuntimeConfig;
18
18
  private clearCurrentSession;
19
+ private validateRuntimeConfig;
19
20
  private loadRuntimeConfig;
20
21
  private cacheCurrentSession;
21
22
  private tryCacheCurrentSession;
@@ -1,11 +1,12 @@
1
- import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
2
1
  import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
2
+ import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
3
3
  import _regeneratorRuntime from "@babel/runtime/helpers/esm/regeneratorRuntime";
4
4
  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
8
  import { createResponseError, getErrorCode, isRecord, readResponsePayload, resolveRuntimeUrl } from "./utils";
9
+ var DEFAULT_AUTH_TOKEN_ENDPOINT = '/runtime/appwrite/auth/custom-token';
9
10
  export var AppwriteSessionCoordinator = /*#__PURE__*/function () {
10
11
  function AppwriteSessionCoordinator(options, request) {
11
12
  _classCallCheck(this, AppwriteSessionCoordinator);
@@ -199,16 +200,40 @@ export var AppwriteSessionCoordinator = /*#__PURE__*/function () {
199
200
  this.state.currentSessionProvider = null;
200
201
  this.state.confirmedQmuseUserId = null;
201
202
  }
203
+ }, {
204
+ key: "validateRuntimeConfig",
205
+ value: function validateRuntimeConfig(config) {
206
+ if (!isRecord(config)) {
207
+ throw new Error('Appwrite runtime config is incomplete');
208
+ }
209
+ var normalized = {
210
+ endpoint: config.endpoint,
211
+ projectId: config.projectId,
212
+ databaseId: config.databaseId
213
+ };
214
+ if (typeof normalized.endpoint !== 'string' || !normalized.endpoint || typeof normalized.projectId !== 'string' || !normalized.projectId || typeof normalized.databaseId !== 'string' || !normalized.databaseId) {
215
+ throw new Error('Appwrite runtime config is incomplete');
216
+ }
217
+ return normalized;
218
+ }
202
219
  }, {
203
220
  key: "loadRuntimeConfig",
204
221
  value: function () {
205
222
  var _loadRuntimeConfig = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee6() {
206
- var runtime, response, payload, data, config;
223
+ var runtime, response, payload, data;
207
224
  return _regeneratorRuntime().wrap(function _callee6$(_context6) {
208
225
  while (1) switch (_context6.prev = _context6.next) {
209
226
  case 0:
227
+ if (!this.options.appwriteConfig) {
228
+ _context6.next = 2;
229
+ break;
230
+ }
231
+ return _context6.abrupt("return", _objectSpread(_objectSpread({}, this.validateRuntimeConfig(this.options.appwriteConfig)), {}, {
232
+ authTokenEndpoint: DEFAULT_AUTH_TOKEN_ENDPOINT
233
+ }));
234
+ case 2:
210
235
  runtime = this.getMuseRuntime();
211
- _context6.next = 3;
236
+ _context6.next = 5;
212
237
  return this.request(resolveRuntimeUrl('/runtime/appwrite/config', runtime.domain), {
213
238
  method: 'POST',
214
239
  credentials: 'include',
@@ -220,15 +245,15 @@ export var AppwriteSessionCoordinator = /*#__PURE__*/function () {
220
245
  env: runtime.env
221
246
  })
222
247
  });
223
- case 3:
248
+ case 5:
224
249
  response = _context6.sent;
225
- _context6.next = 6;
250
+ _context6.next = 8;
226
251
  return readResponsePayload(response);
227
- case 6:
252
+ case 8:
228
253
  payload = _context6.sent;
229
254
  data = isRecord(payload === null || payload === void 0 ? void 0 : payload.data) ? payload.data : null;
230
255
  if (!(!response.ok || (payload === null || payload === void 0 ? void 0 : payload.success) !== true || !data)) {
231
- _context6.next = 10;
256
+ _context6.next = 12;
232
257
  break;
233
258
  }
234
259
  throw createResponseError({
@@ -237,21 +262,21 @@ export var AppwriteSessionCoordinator = /*#__PURE__*/function () {
237
262
  fallbackMessage: "Appwrite config request failed: ".concat(response.status),
238
263
  fallbackType: 'appwrite_config_error'
239
264
  });
240
- case 10:
241
- config = {
242
- endpoint: data.endpoint,
243
- projectId: data.projectId,
244
- databaseId: data.databaseId,
245
- authTokenEndpoint: data.authTokenEndpoint
246
- };
247
- if (!(typeof config.endpoint !== 'string' || !config.endpoint || typeof config.projectId !== 'string' || !config.projectId || typeof config.databaseId !== 'string' || !config.databaseId || typeof config.authTokenEndpoint !== 'string' || !config.authTokenEndpoint)) {
248
- _context6.next = 13;
265
+ case 12:
266
+ if (!(typeof data.authTokenEndpoint !== 'string' || !data.authTokenEndpoint)) {
267
+ _context6.next = 14;
249
268
  break;
250
269
  }
251
270
  throw new Error('Appwrite runtime config is incomplete');
252
- case 13:
253
- return _context6.abrupt("return", config);
254
271
  case 14:
272
+ return _context6.abrupt("return", _objectSpread(_objectSpread({}, this.validateRuntimeConfig({
273
+ endpoint: data.endpoint,
274
+ projectId: data.projectId,
275
+ databaseId: data.databaseId
276
+ })), {}, {
277
+ authTokenEndpoint: data.authTokenEndpoint
278
+ }));
279
+ case 15:
255
280
  case "end":
256
281
  return _context6.stop();
257
282
  }
package/dist/types.d.ts CHANGED
@@ -10,7 +10,6 @@ export interface AppwriteRuntimeConfig {
10
10
  endpoint: string;
11
11
  projectId: string;
12
12
  databaseId: string;
13
- authTokenEndpoint: string;
14
13
  }
15
14
  export interface AppwriteUser {
16
15
  $id: string;
@@ -83,6 +82,7 @@ export interface AppwriteTablesDBLike {
83
82
  interface QmuseAppwriteRuntimeBaseOptions {
84
83
  getMuseRuntime(): QmuseRuntimeContext;
85
84
  getQmuseLoginUserId(): string | null;
85
+ appwriteConfig?: AppwriteRuntimeConfig;
86
86
  }
87
87
  interface QmuseAppwriteInjectedClientsOptions extends QmuseAppwriteRuntimeBaseOptions {
88
88
  client: AppwriteClientLike;
@@ -92,6 +92,7 @@ interface QmuseAppwriteInjectedClientsOptions extends QmuseAppwriteRuntimeBaseOp
92
92
  storage?: never;
93
93
  }
94
94
  interface QmuseAppwritePortableRuntimeOptions extends QmuseAppwriteRuntimeBaseOptions, PortableAppwriteClientsOptions {
95
+ appwriteConfig: AppwriteRuntimeConfig;
95
96
  client?: never;
96
97
  account?: never;
97
98
  tablesDB?: never;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qmuse/appwrite-runtime-sdk",
3
- "version": "1.0.5-dev.2",
3
+ "version": "1.0.5-dev.3",
4
4
  "description": "QMuse Appwrite browser runtime SDK",
5
5
  "repository": {
6
6
  "type": "git",