@chipmobilesdk/rn-ai 0.4.0 → 0.5.0

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.
Files changed (88) hide show
  1. package/CHANGELOG.md +120 -0
  2. package/README.md +5 -2
  3. package/lib/commonjs/config/behaviorConfig.js +283 -0
  4. package/lib/commonjs/config/behaviorConfig.js.map +1 -0
  5. package/lib/commonjs/contract/gateway.js +60 -0
  6. package/lib/commonjs/contract/gateway.js.map +1 -0
  7. package/lib/commonjs/core/aiClient.js +330 -0
  8. package/lib/commonjs/core/aiClient.js.map +1 -0
  9. package/lib/commonjs/core/quotaRequest.js +105 -0
  10. package/lib/commonjs/core/quotaRequest.js.map +1 -0
  11. package/lib/commonjs/diagnostics/errors.js +108 -0
  12. package/lib/commonjs/diagnostics/errors.js.map +1 -0
  13. package/lib/commonjs/diagnostics/messageKeys.js +68 -0
  14. package/lib/commonjs/diagnostics/messageKeys.js.map +1 -0
  15. package/lib/commonjs/index.js +102 -0
  16. package/lib/commonjs/index.js.map +1 -0
  17. package/lib/commonjs/package.json +1 -0
  18. package/lib/commonjs/react/hooks.js +170 -0
  19. package/lib/commonjs/react/hooks.js.map +1 -0
  20. package/lib/commonjs/transport/sseClient.js +151 -0
  21. package/lib/commonjs/transport/sseClient.js.map +1 -0
  22. package/lib/commonjs/transport/timeouts.js +46 -0
  23. package/lib/commonjs/transport/timeouts.js.map +1 -0
  24. package/lib/module/config/behaviorConfig.js +275 -0
  25. package/lib/module/config/behaviorConfig.js.map +1 -0
  26. package/lib/module/contract/gateway.js +56 -0
  27. package/lib/module/contract/gateway.js.map +1 -0
  28. package/lib/module/core/aiClient.js +327 -0
  29. package/lib/module/core/aiClient.js.map +1 -0
  30. package/lib/module/core/quotaRequest.js +102 -0
  31. package/lib/module/core/quotaRequest.js.map +1 -0
  32. package/lib/module/diagnostics/errors.js +99 -0
  33. package/lib/module/diagnostics/errors.js.map +1 -0
  34. package/lib/module/diagnostics/messageKeys.js +61 -0
  35. package/lib/module/diagnostics/messageKeys.js.map +1 -0
  36. package/lib/module/index.js +19 -0
  37. package/lib/module/index.js.map +1 -0
  38. package/lib/module/package.json +1 -0
  39. package/lib/module/react/hooks.js +164 -0
  40. package/lib/module/react/hooks.js.map +1 -0
  41. package/lib/module/transport/sseClient.js +146 -0
  42. package/lib/module/transport/sseClient.js.map +1 -0
  43. package/lib/module/transport/timeouts.js +41 -0
  44. package/lib/module/transport/timeouts.js.map +1 -0
  45. package/lib/typescript/commonjs/config/behaviorConfig.d.ts +119 -0
  46. package/lib/typescript/commonjs/config/behaviorConfig.d.ts.map +1 -0
  47. package/lib/typescript/commonjs/contract/gateway.d.ts +64 -0
  48. package/lib/typescript/commonjs/contract/gateway.d.ts.map +1 -0
  49. package/lib/typescript/commonjs/core/aiClient.d.ts +104 -0
  50. package/lib/typescript/commonjs/core/aiClient.d.ts.map +1 -0
  51. package/lib/typescript/commonjs/core/quotaRequest.d.ts +45 -0
  52. package/lib/typescript/commonjs/core/quotaRequest.d.ts.map +1 -0
  53. package/lib/typescript/commonjs/diagnostics/errors.d.ts +38 -0
  54. package/lib/typescript/commonjs/diagnostics/errors.d.ts.map +1 -0
  55. package/lib/typescript/commonjs/diagnostics/messageKeys.d.ts +46 -0
  56. package/lib/typescript/commonjs/diagnostics/messageKeys.d.ts.map +1 -0
  57. package/lib/typescript/commonjs/index.d.ts +21 -0
  58. package/lib/typescript/commonjs/index.d.ts.map +1 -0
  59. package/lib/typescript/commonjs/package.json +1 -0
  60. package/lib/typescript/commonjs/react/hooks.d.ts +37 -0
  61. package/lib/typescript/commonjs/react/hooks.d.ts.map +1 -0
  62. package/lib/typescript/commonjs/transport/sseClient.d.ts +57 -0
  63. package/lib/typescript/commonjs/transport/sseClient.d.ts.map +1 -0
  64. package/lib/typescript/commonjs/transport/timeouts.d.ts +28 -0
  65. package/lib/typescript/commonjs/transport/timeouts.d.ts.map +1 -0
  66. package/lib/typescript/module/config/behaviorConfig.d.ts +119 -0
  67. package/lib/typescript/module/config/behaviorConfig.d.ts.map +1 -0
  68. package/lib/typescript/module/contract/gateway.d.ts +64 -0
  69. package/lib/typescript/module/contract/gateway.d.ts.map +1 -0
  70. package/lib/typescript/module/core/aiClient.d.ts +104 -0
  71. package/lib/typescript/module/core/aiClient.d.ts.map +1 -0
  72. package/lib/typescript/module/core/quotaRequest.d.ts +45 -0
  73. package/lib/typescript/module/core/quotaRequest.d.ts.map +1 -0
  74. package/lib/typescript/module/diagnostics/errors.d.ts +38 -0
  75. package/lib/typescript/module/diagnostics/errors.d.ts.map +1 -0
  76. package/lib/typescript/module/diagnostics/messageKeys.d.ts +46 -0
  77. package/lib/typescript/module/diagnostics/messageKeys.d.ts.map +1 -0
  78. package/lib/typescript/module/index.d.ts +21 -0
  79. package/lib/typescript/module/index.d.ts.map +1 -0
  80. package/lib/typescript/module/package.json +1 -0
  81. package/lib/typescript/module/react/hooks.d.ts +37 -0
  82. package/lib/typescript/module/react/hooks.d.ts.map +1 -0
  83. package/lib/typescript/module/transport/sseClient.d.ts +57 -0
  84. package/lib/typescript/module/transport/sseClient.d.ts.map +1 -0
  85. package/lib/typescript/module/transport/timeouts.d.ts +28 -0
  86. package/lib/typescript/module/transport/timeouts.d.ts.map +1 -0
  87. package/package.json +40 -12
  88. package/skills/sdk-rn-ai/SKILL.md +8 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAiB,CAAC;AACjD,YAAY,EACX,QAAQ,EACR,cAAc,EACd,eAAe,EACf,aAAa,EACb,yBAAyB,EACzB,WAAW,EACX,WAAW,EACX,WAAW,EACX,kBAAkB,EAClB,UAAU,EACV,KAAK,EACL,aAAa,GACb,MAAM,oBAAiB,CAAC;AAEzB,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,4BAAyB,CAAC;AAC/F,OAAO,EAAE,uBAAuB,EAAE,wBAAwB,EAAE,MAAM,4BAAyB,CAAC;AAI5F,YAAY,EACX,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,EACZ,kBAAkB,EAClB,YAAY,EACZ,eAAe,EACf,gBAAgB,GAChB,MAAM,uBAAoB,CAAC;AAC5B,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,uBAAoB,CAAC;AAE5F,YAAY,EAAE,UAAU,EAAE,MAAM,yBAAsB,CAAC;AACvD,YAAY,EACX,UAAU,EACV,WAAW,EACX,SAAS,EACT,eAAe,EACf,eAAe,GACf,MAAM,0BAAuB,CAAC;AAC/B,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,kBAAe,CAAC;AAC1E,YAAY,EACX,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,gBAAgB,GAChB,MAAM,kBAAe,CAAC;AAEvB,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAsB,CAAC;AAC1D,YAAY,EAAE,WAAW,EAAE,MAAM,yBAAsB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,8BAA2B,CAAC;AACpG,YAAY,EAAE,YAAY,EAAE,MAAM,8BAA2B,CAAC"}
@@ -0,0 +1 @@
1
+ {"type":"module"}
@@ -0,0 +1,37 @@
1
+ import type { AiBehaviorState, AiClient, ChatRequest, QuotaSnapshot } from '../core/aiClient.js';
2
+ import type { AiError } from '../diagnostics/errors.js';
3
+ export type AiChatStatus = 'idle' | 'loading' | 'streaming' | 'done' | 'error' | 'rate-limited';
4
+ export interface UseAiChatResult {
5
+ send(request: ChatRequest): void;
6
+ cancel(): void;
7
+ status: AiChatStatus;
8
+ /** Accumulated streamed text, flushed on an interval rather than per token. */
9
+ text: string;
10
+ error?: AiError;
11
+ retryAt?: Date;
12
+ quota?: QuotaSnapshot;
13
+ }
14
+ export interface UseAiChatOptions {
15
+ /**
16
+ * How often the accumulated text reaches the screen, in milliseconds.
17
+ *
18
+ * A model streams 30–100 tokens a second, and a render per token is 30–100
19
+ * renders of the whole transcript a second on the JS thread (PERF-12). At the
20
+ * default a long answer costs about 20 renders a second instead, and the last
21
+ * tokens are always flushed with the terminal state. `0` renders per token.
22
+ */
23
+ flushIntervalMs?: number;
24
+ }
25
+ export declare function useAiChat(client: AiClient, options?: UseAiChatOptions): UseAiChatResult;
26
+ export interface UseAiQuotaResult {
27
+ quota?: QuotaSnapshot;
28
+ status: 'loading' | 'ready' | 'error';
29
+ refresh(): void;
30
+ }
31
+ export declare function useAiQuota(client: AiClient): UseAiQuotaResult;
32
+ /**
33
+ * The client's behavior state (config source and whether AI is enabled), live:
34
+ * re-renders when the kill switch flips or the config state moves (AI-09).
35
+ */
36
+ export declare function useAiBehaviorState(client: AiClient): AiBehaviorState;
37
+ //# sourceMappingURL=hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../../../src/react/hooks.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACX,eAAe,EACf,QAAQ,EAER,WAAW,EACX,aAAa,EACb,MAAM,qBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,0BAAuB,CAAC;AAErD,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,SAAS,GAAG,WAAW,GAAG,MAAM,GAAG,OAAO,GAAG,cAAc,CAAC;AAEhG,MAAM,WAAW,eAAe;IAC/B,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;IACjC,MAAM,IAAI,IAAI,CAAC;IACf,MAAM,EAAE,YAAY,CAAC;IACrB,+EAA+E;IAC/E,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,IAAI,CAAC;IACf,KAAK,CAAC,EAAE,aAAa,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAChC;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CACzB;AAID,wBAAgB,SAAS,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAE,gBAAqB,GAAG,eAAe,CA2G3F;AAED,MAAM,WAAW,gBAAgB;IAChC,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,MAAM,EAAE,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC;IACtC,OAAO,IAAI,IAAI,CAAC;CAChB;AAgBD,wBAAgB,UAAU,CAAC,MAAM,EAAE,QAAQ,GAAG,gBAAgB,CAqC7D;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,QAAQ,GAAG,eAAe,CAEpE"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Minimal SSE reader over XMLHttpRequest (research R2).
3
+ *
4
+ * React Native's fetch does not reliably expose ReadableStream on Hermes, so
5
+ * we use XHR incremental text delivery (readyState LOADING + onprogress) —
6
+ * the same mechanism community SSE libraries use — with zero dependencies.
7
+ * The gateway never compresses SSE responses (contract), which keeps
8
+ * incremental delivery intact on both platforms.
9
+ */
10
+ export interface SseRequest {
11
+ url: string;
12
+ method?: 'GET' | 'POST';
13
+ headers?: Record<string, string>;
14
+ /** JSON string body for POST requests. */
15
+ body?: string;
16
+ /** Hard limit on the whole request. Rarely right for a stream; prefer the two below. */
17
+ timeoutMs?: number;
18
+ /** Fails with `onError(0, 'timeout')` if response headers have not arrived by then. */
19
+ connectTimeoutMs?: number;
20
+ /** Fails with `onError(0, 'timeout')` when no chunk arrives for this long. Reset per chunk. */
21
+ idleTimeoutMs?: number;
22
+ }
23
+ /** What the response said besides its body. Absent for a failure with no response. */
24
+ export interface SseResponseInfo {
25
+ /** A response header, or null. `Retry-After` is the one this package reads. */
26
+ getHeader(name: string): string | null;
27
+ }
28
+ export interface SseHandlers {
29
+ /** One call per `data:` event payload (raw string, already de-framed). */
30
+ onData(payload: string): void;
31
+ /** Stream closed normally (transport level; `[DONE]` handling is the caller's). */
32
+ onEnd(): void;
33
+ /** Transport or HTTP error. `status` is 0 for network failures. */
34
+ onError(status: number, bodyText: string, response?: SseResponseInfo): void;
35
+ }
36
+ export interface SseHandle {
37
+ cancel(): void;
38
+ }
39
+ /**
40
+ * The transport port: how this package makes a streaming request.
41
+ *
42
+ * A published port rather than `typeof requestSse`, so the default reader's
43
+ * own signature is not part of the public API (AI-18): an app may inject its
44
+ * own transport, and this package may change how `requestSse` is written
45
+ * without that being a breaking change.
46
+ */
47
+ export type StreamTransport = (request: SseRequest, handlers: SseHandlers) => SseHandle;
48
+ /**
49
+ * Parse complete `data:` events out of `text` starting at `fromIndex`.
50
+ *
51
+ * Both line endings are accepted. A proxy that normalises to CRLF — an API
52
+ * gateway or a corporate middlebox — used to make every event invisible until
53
+ * the stream closed, because only `\n\n` counted as a separator (AI-22).
54
+ */
55
+ export declare function drainSseEvents(text: string, fromIndex: number, emit: (payload: string) => void): number;
56
+ export declare function requestSse(request: SseRequest, handlers: SseHandlers): SseHandle;
57
+ //# sourceMappingURL=sseClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sseClient.d.ts","sourceRoot":"","sources":["../../../../src/transport/sseClient.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,WAAW,UAAU;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,0CAA0C;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wFAAwF;IACxF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uFAAuF;IACvF,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,+FAA+F;IAC/F,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,sFAAsF;AACtF,MAAM,WAAW,eAAe;IAC/B,+EAA+E;IAC/E,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;CACvC;AAED,MAAM,WAAW,WAAW;IAC3B,0EAA0E;IAC1E,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,mFAAmF;IACnF,KAAK,IAAI,IAAI,CAAC;IACd,mEAAmE;IACnE,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;CAC5E;AAED,MAAM,WAAW,SAAS;IACzB,MAAM,IAAI,IAAI,CAAC;CACf;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,WAAW,KAAK,SAAS,CAAC;AAExF;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC7B,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAC7B,MAAM,CAiBR;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,WAAW,GAAG,SAAS,CA0GhF"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Time limits for every network call the client makes (AI-04).
3
+ *
4
+ * Without them a stalled mobile connection left `useAiChat` in `loading` or
5
+ * `streaming`, and `useAiQuota` in `loading`, until the user gave up.
6
+ */
7
+ export interface AiTimeouts {
8
+ /** Request sent → response headers received, for the chat stream. */
9
+ connectMs: number;
10
+ /** Longest silence allowed between two chunks of the chat stream. */
11
+ idleMs: number;
12
+ /** Behavior-config fetch, including reading the body. */
13
+ configMs: number;
14
+ /** Quota fetch, including reading the body. */
15
+ quotaMs: number;
16
+ }
17
+ /**
18
+ * The gateway sends headers only once the model has answered, so `connectMs`
19
+ * also covers time to first token on a large image prompt.
20
+ */
21
+ export declare const DEFAULT_AI_TIMEOUTS: AiTimeouts;
22
+ /**
23
+ * Runs `run` with an abort signal and rejects with `onTimeout()` after `ms`.
24
+ * The race matters as much as the signal: an injected `fetchFn` (or an old
25
+ * polyfill) may ignore the signal entirely.
26
+ */
27
+ export declare function withTimeout<T>(ms: number, run: (signal: AbortSignal | undefined) => Promise<T>, onTimeout: () => Error): Promise<T>;
28
+ //# sourceMappingURL=timeouts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timeouts.d.ts","sourceRoot":"","sources":["../../../../src/transport/timeouts.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,UAAU;IAC1B,qEAAqE;IACrE,SAAS,EAAE,MAAM,CAAC;IAClB,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAC;IACf,yDAAyD;IACzD,QAAQ,EAAE,MAAM,CAAC;IACjB,+CAA+C;IAC/C,OAAO,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,eAAO,MAAM,mBAAmB,EAAE,UAKjC,CAAC;AAEF;;;;GAIG;AACH,wBAAsB,WAAW,CAAC,CAAC,EAClC,EAAE,EAAE,MAAM,EACV,GAAG,EAAE,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,EACpD,SAAS,EAAE,MAAM,KAAK,GACpB,OAAO,CAAC,CAAC,CAAC,CAcZ"}
package/package.json CHANGED
@@ -1,15 +1,23 @@
1
1
  {
2
2
  "name": "@chipmobilesdk/rn-ai",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "private": false,
5
5
  "license": "UNLICENSED",
6
- "main": "src/index.ts",
7
- "types": "src/index.ts",
6
+ "source": "./src/index.ts",
7
+ "main": "./lib/commonjs/index.js",
8
+ "module": "./lib/module/index.js",
9
+ "types": "./lib/typescript/commonjs/index.d.ts",
8
10
  "exports": {
9
11
  ".": {
10
- "types": "./src/index.ts",
11
- "react-native": "./src/index.ts",
12
- "default": "./src/index.ts"
12
+ "chipmobilesdk-source": "./src/index.ts",
13
+ "import": {
14
+ "types": "./lib/typescript/module/index.d.ts",
15
+ "default": "./lib/module/index.js"
16
+ },
17
+ "require": {
18
+ "types": "./lib/typescript/commonjs/index.d.ts",
19
+ "default": "./lib/commonjs/index.js"
20
+ }
13
21
  }
14
22
  },
15
23
  "files": [
@@ -17,23 +25,43 @@
17
25
  "!src/**/__tests__",
18
26
  "skills",
19
27
  "README.md",
20
- "CHANGELOG.md"
28
+ "CHANGELOG.md",
29
+ "lib"
21
30
  ],
22
31
  "sideEffects": false,
23
32
  "scripts": {
33
+ "build": "bob build",
24
34
  "typecheck": "tsc -p tsconfig.json && tsc -p tsconfig.test.json",
25
- "pack:check": "npm pack --dry-run"
35
+ "pack:check": "npm pack --dry-run",
36
+ "prepack": "npm run build"
26
37
  },
27
38
  "dependencies": {
28
- "@chipmobilesdk/rn-core": "^0.1.0"
39
+ "@chipmobilesdk/rn-core": "^0.2.0"
29
40
  },
30
41
  "peerDependencies": {
31
- "@chipmobilesdk/rn-auth": ">=0.2.0",
32
- "react": ">=19",
33
- "react-native": ">=0.85"
42
+ "react": ">=19"
34
43
  },
35
44
  "publishConfig": {
36
45
  "access": "public",
37
46
  "registry": "https://registry.npmjs.org/"
47
+ },
48
+ "react-native-builder-bob": {
49
+ "source": "src",
50
+ "output": "lib",
51
+ "targets": [
52
+ [
53
+ "commonjs",
54
+ {
55
+ "esm": true
56
+ }
57
+ ],
58
+ [
59
+ "module",
60
+ {
61
+ "esm": true
62
+ }
63
+ ],
64
+ "typescript"
65
+ ]
38
66
  }
39
67
  }
@@ -19,6 +19,14 @@ and a typed error model.
19
19
  - Handling AI request failure, cancellation, or streaming state
20
20
  - Localising AI-related user messages
21
21
 
22
+ ## The token source is an interface, not rn-auth
23
+
24
+ `createAiClient` takes `auth: TokenProvider` — one method,
25
+ `requestAccessToken(resourceKey, { forceRefresh })`. rn-auth's controller satisfies it,
26
+ so passing `auth` straight in is the usual wiring, but rn-auth is not a dependency or a
27
+ peer of this package: an app with its own token source implements the interface and
28
+ installs nothing extra. Do not reach for anything else on the object you pass.
29
+
22
30
  ## The app owns more than you expect
23
31
 
24
32
  This package deliberately does not handle everything. The README has an