@goplus123/core-api 1.0.6 → 1.0.8

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
@@ -260,11 +260,19 @@ const sdk = initSDK({
260
260
 
261
261
  对应实现:[`initSDK`](./src/index.ts#L372-L578)
262
262
 
263
- ### React Native:注入 gRPC invoker(解决 RN 真机解析 gRPC-Web 响应问题)
263
+ ### React Native:配置 gRPC invoker(Invoke)(解决 RN 真机 gRPC-Web 兼容问题)
264
264
 
265
265
  当后端仅提供 gRPC-Web,而 React Native 环境下 `@connectrpc/connect-web` 的 `fetch`/二进制响应解析存在兼容性问题时,可以通过 `grpc.invoker` 注入一层“可替换的底层调用器”,在不改动上层调用方式(`sdk.xxx` / `requestApi` / spec)前提下,切换为 RN 可用的 gRPC-Web 实现。
266
266
 
267
267
  这个 `invoker` 只是一个“可插拔的 unary 调用实现”,不限定必须使用某个第三方库。
268
+ 内置的 `builtin` invoker 使用的是 gRPC-Web(二进制)协议:`application/grpc-web+proto`。
269
+
270
+ `grpc.invoker` 支持两种形态(优先级从高到低):
271
+
272
+ - `invoker: GrpcInvoker`:使用外部传入的自定义 invoker
273
+ - `invoker: 'builtin'`:使用 SDK 内置的 gRPC-Web unary invoker(基于 `fetch` + `toBinary/fromBinary`)
274
+
275
+ 注意:使用 `invoker: 'builtin'` 时,请确保 `grpc.protocol` 为 `'grpc-web'`。
268
276
 
269
277
  `invoker.unary()` 的入参约定:
270
278
 
@@ -275,7 +283,37 @@ const sdk = initSDK({
275
283
  - `headers`:最终要发出去的 headers(已合并 auth/getHeaders/静态 headers 与 callOptions.headers)
276
284
  - `callOptions`:透传的调用选项(例如 timeout),按你的底层实现自行使用
277
285
 
278
- 示例 A(推荐):在 RN 工程内用 `fetch` 走 gRPC-Web(二进制),复用本 SDK 的 bufbuild 生成物(不需要重新编译 proto)。这个方案不需要引入 `@improbable-eng/grpc-web-react-native-transport`:
286
+ 示例 0(推荐):直接启用内置 invoker(不需要在 RN 工程维护一套 invoke 代码):
287
+
288
+ ```ts
289
+ import { initSDK, fetchGuid } from '@goplus123/core-api'
290
+
291
+ const sdk = initSDK({
292
+ ws: {
293
+ url: 'wss://example.com/websocket',
294
+ protocols: fetchGuid(),
295
+ },
296
+ grpc: {
297
+ baseUrl: 'https://example.com/cms',
298
+ protocol: 'grpc-web',
299
+ invoker: 'builtin',
300
+ },
301
+ http: {
302
+ baseUrl: 'https://example.com/api',
303
+ },
304
+ headerConfig: {
305
+ version: '1.0.0',
306
+ platformId: '50',
307
+ isReload: false,
308
+ deviceType: 1,
309
+ deviceId: '',
310
+ childPlatformId: '50',
311
+ },
312
+ defaultTransport: 'auto',
313
+ })
314
+ ```
315
+
316
+ 示例 A(自定义):在 RN 工程内用 `fetch` 走 gRPC-Web(二进制),复用本 SDK 的 bufbuild 生成物(不需要重新编译 proto)。这个方案不需要引入 `@improbable-eng/grpc-web-react-native-transport`:
279
317
 
280
318
  ```ts
281
319
  import { initSDK, fetchGuid } from '@goplus123/core-api'
@@ -352,6 +390,49 @@ function capitalizeRpcName(methodName: string): string {
352
390
  return methodName[0]!.toUpperCase() + methodName.slice(1)
353
391
  }
354
392
 
393
+ function resolveServiceMethod(service: any, methodName: string, method?: any): any | undefined {
394
+ if (method) return method
395
+
396
+ const expectedLocalName = methodName
397
+ const expectedRpcName = capitalizeRpcName(methodName)
398
+
399
+ const direct = service?.method
400
+ if (Array.isArray(direct)) {
401
+ return direct.find((m: any) => {
402
+ const localName = String(m?.localName ?? '')
403
+ const rpcName = String(m?.name ?? '')
404
+ return (
405
+ localName === expectedLocalName ||
406
+ localName === expectedRpcName ||
407
+ rpcName === expectedLocalName ||
408
+ rpcName === expectedRpcName
409
+ )
410
+ })
411
+ }
412
+ if (direct && typeof direct === 'object') {
413
+ return (direct as any)[expectedLocalName] ?? (direct as any)[expectedRpcName]
414
+ }
415
+
416
+ const methods = service?.methods
417
+ if (Array.isArray(methods)) {
418
+ return methods.find((m: any) => {
419
+ const localName = String(m?.localName ?? '')
420
+ const rpcName = String(m?.name ?? '')
421
+ return (
422
+ localName === expectedLocalName ||
423
+ localName === expectedRpcName ||
424
+ rpcName === expectedLocalName ||
425
+ rpcName === expectedRpcName
426
+ )
427
+ })
428
+ }
429
+ if (methods && typeof methods === 'object') {
430
+ return (methods as any)[expectedLocalName] ?? (methods as any)[expectedRpcName]
431
+ }
432
+
433
+ return undefined
434
+ }
435
+
355
436
  function getGrpcWebPath(service: any, methodName: string, method: any): string {
356
437
  const typeName = String(service?.typeName ?? '')
357
438
  const rpcName = String(method?.name ?? method?.rpc?.name ?? '') || capitalizeRpcName(methodName)
@@ -367,14 +448,7 @@ async function rnGrpcWebUnary(args: {
367
448
  headers: Record<string, string>
368
449
  callOptions?: { timeoutMs?: number }
369
450
  }): Promise<any> {
370
- const method =
371
- args.method ??
372
- (() => {
373
- const ms = args.service?.methods
374
- if (Array.isArray(ms)) return ms.find((m: any) => m?.localName === args.methodName || m?.name === args.methodName)
375
- if (ms && typeof ms === 'object') return (ms as any)[args.methodName]
376
- return undefined
377
- })()
451
+ const method = resolveServiceMethod(args.service, args.methodName, args.method)
378
452
  if (!method) {
379
453
  throw new Error(`gRPC method not found: ${String(args.service?.typeName ?? '')}.${args.methodName}`)
380
454
  }
@@ -447,7 +521,10 @@ const sdk = initSDK({
447
521
  })
448
522
  ```
449
523
 
450
- 补充说明:如果你已经在 RN 工程里有基于 `@improbable-eng/grpc-web` / `@improbable-eng/grpc-web-react-native-transport` 的 `rnGrpcWebUnary` 封装,也可以直接把它塞进 `invoker.unary`。但需要确保它能消费本 SDK 生成的 bufbuild message 与 schema(`toBinary/fromBinary`),否则通常会因为“message/descriptor 体系不一致”(improbable 常见搭配是另一套 proto 生成物)而对不上类型与序列化方式。
524
+ 补充说明:
525
+
526
+ - 自定义 invoker 时,建议优先使用 `args.method`(SDK 解析好的方法描述),避免在 RN 侧重复解析 `service.method/service.methods` 的结构差异。
527
+ - 如果你已经在 RN 工程里有基于 `@improbable-eng/grpc-web` / `@improbable-eng/grpc-web-react-native-transport` 的 `rnGrpcWebUnary` 封装,也可以直接把它塞进 `invoker.unary`。但需要确保它能消费本 SDK 生成的 bufbuild message 与 schema(`toBinary/fromBinary`),否则通常会因为“message/descriptor 体系不一致”(improbable 常见搭配是另一套 proto 生成物)而对不上类型与序列化方式。
451
528
 
452
529
  ### 2) 直接调用(推荐)
453
530