@chipmobilesdk/rn-ai 0.3.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 (97) hide show
  1. package/CHANGELOG.md +146 -0
  2. package/README.md +65 -24
  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 +43 -4
  89. package/src/config/behaviorConfig.ts +158 -37
  90. package/src/contract/gateway.ts +91 -0
  91. package/src/core/aiClient.ts +194 -96
  92. package/src/core/quotaRequest.ts +125 -0
  93. package/src/diagnostics/errors.ts +85 -23
  94. package/src/diagnostics/messageKeys.ts +3 -0
  95. package/src/index.ts +28 -1
  96. package/src/react/hooks.ts +86 -14
  97. package/src/transport/sseClient.ts +58 -11
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.SSE_DONE_SENTINEL = exports.RETRY_AFTER_HEADER = exports.QUOTA_HEADERS = exports.GATEWAY_ERROR_STATUS = void 0;
7
+ /**
8
+ * The gateway↔client contract: error codes, quota headers, stream events.
9
+ *
10
+ * One definition, imported by both sides (GW-13). The gateway's own codes and
11
+ * the client's map of them were two hand-maintained lists, and they had already
12
+ * drifted: `BAD_REQUEST`, `ENDPOINT_RETIRED` and `INTERNAL` existed on the
13
+ * server and were unknown to the client, which fell back to a guess from the
14
+ * status. Adding a code now fails to compile on whichever side has not handled
15
+ * it.
16
+ *
17
+ * Types and plain constants only, and no import of anything: the gateway runs
18
+ * on Node and imports this file for its types alone.
19
+ */
20
+
21
+ /** Every error the gateway answers with (`error.code` in the body). */
22
+
23
+ /** The HTTP status each code is sent with. */
24
+ const GATEWAY_ERROR_STATUS = exports.GATEWAY_ERROR_STATUS = {
25
+ BAD_REQUEST: 400,
26
+ AUTH_INVALID: 401,
27
+ NOT_ENTITLED: 403,
28
+ USER_BLOCKED: 403,
29
+ APP_UNKNOWN: 404,
30
+ ENDPOINT_RETIRED: 410,
31
+ PAYLOAD_TOO_LARGE: 413,
32
+ MODALITY_NOT_ALLOWED: 415,
33
+ RATE_LIMITED: 429,
34
+ UPSTREAM_BUSY: 429,
35
+ UPSTREAM_ERROR: 500,
36
+ INTERNAL: 500
37
+ };
38
+
39
+ /** The error body. `message` is safe to log; it never carries upstream detail. */
40
+
41
+ /** The quota headers, by name. A rename here breaks both sides' compile. */
42
+ const QUOTA_HEADERS = exports.QUOTA_HEADERS = {
43
+ minuteRemaining: 'X-Quota-Minute-Remaining',
44
+ dayRemaining: 'X-Quota-Day-Remaining',
45
+ dayTokensRemaining: 'X-Quota-Day-Tokens-Remaining'
46
+ };
47
+
48
+ /** The names field by field, so a side declaring its own literals is checked exactly. */
49
+
50
+ /** What is left of an app's allowance, as the gateway reports it. */
51
+
52
+ /** What one answer cost. */
53
+
54
+ /** The `data:` payloads of a chat stream, before the `[DONE]` sentinel. */
55
+
56
+ /** The last `data:` line of a stream that completed. */
57
+ const SSE_DONE_SENTINEL = exports.SSE_DONE_SENTINEL = '[DONE]';
58
+ /** The `Retry-After` header, which a 429 always carries. */
59
+ const RETRY_AFTER_HEADER = exports.RETRY_AFTER_HEADER = 'Retry-After';
60
+ //# sourceMappingURL=gateway.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["GATEWAY_ERROR_STATUS","exports","BAD_REQUEST","AUTH_INVALID","NOT_ENTITLED","USER_BLOCKED","APP_UNKNOWN","ENDPOINT_RETIRED","PAYLOAD_TOO_LARGE","MODALITY_NOT_ALLOWED","RATE_LIMITED","UPSTREAM_BUSY","UPSTREAM_ERROR","INTERNAL","QUOTA_HEADERS","minuteRemaining","dayRemaining","dayTokensRemaining","SSE_DONE_SENTINEL","RETRY_AFTER_HEADER"],"sourceRoot":"../../../src","sources":["contract/gateway.ts"],"mappings":";;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAeA;AACO,MAAMA,oBAAgE,GAAAC,OAAA,CAAAD,oBAAA,GAAG;EAC/EE,WAAW,EAAE,GAAG;EAChBC,YAAY,EAAE,GAAG;EACjBC,YAAY,EAAE,GAAG;EACjBC,YAAY,EAAE,GAAG;EACjBC,WAAW,EAAE,GAAG;EAChBC,gBAAgB,EAAE,GAAG;EACrBC,iBAAiB,EAAE,GAAG;EACtBC,oBAAoB,EAAE,GAAG;EACzBC,YAAY,EAAE,GAAG;EACjBC,aAAa,EAAE,GAAG;EAClBC,cAAc,EAAE,GAAG;EACnBC,QAAQ,EAAE;AACX,CAAC;;AAED;;AASA;AACO,MAAMC,aAAa,GAAAb,OAAA,CAAAa,aAAA,GAAG;EAC5BC,eAAe,EAAE,0BAA0B;EAC3CC,YAAY,EAAE,uBAAuB;EACrCC,kBAAkB,EAAE;AACrB,CAAU;;AAEV;;AAIA;;AAOA;;AAOA;;AAMA;AACO,MAAMC,iBAAiB,GAAAjB,OAAA,CAAAiB,iBAAA,GAAG,QAAQ;AAGzC;AACO,MAAMC,kBAAkB,GAAAlB,OAAA,CAAAkB,kBAAA,GAAG,aAAa","ignoreList":[]}
@@ -0,0 +1,330 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.createAiClient = createAiClient;
7
+ var _rnCore = require("@chipmobilesdk/rn-core");
8
+ var _behaviorConfig = require("../config/behaviorConfig.js");
9
+ var _gateway = require("../contract/gateway.js");
10
+ var _errors = require("../diagnostics/errors.js");
11
+ var _sseClient = require("../transport/sseClient.js");
12
+ var _quotaRequest = require("./quotaRequest.js");
13
+ var _timeouts = require("../transport/timeouts.js");
14
+ /** Every failure a caller receives also goes to the app's SDK sinks (CORE-08). */
15
+ const channel = (0, _rnCore.createDiagnosticChannel)('rn-ai');
16
+ function report(operation, error) {
17
+ channel.emit(error.code, error.retryable ? 'warn' : 'error', {
18
+ operation,
19
+ retryable: error.retryable
20
+ });
21
+ }
22
+
23
+ /** Minimal slice of the rn-auth `Auth` controller the client needs. */
24
+
25
+ /** What one answer cost, as the gateway reports it. */
26
+
27
+ /** What is left of the app's allowance. */
28
+
29
+ /** Ceiling on one remote-configured backoff step, so a bad document cannot stall a chat. */
30
+ const MAX_RETRY_BACKOFF_MS = 30_000;
31
+
32
+ /** The wait before silent retry `index` (0-based); the last configured step repeats. */
33
+ function backoffBefore(steps, index) {
34
+ const step = steps[Math.min(index, steps.length - 1)] ?? 0;
35
+ return Math.min(Math.max(0, step), MAX_RETRY_BACKOFF_MS);
36
+ }
37
+ /** A quota from the wire, or nothing: a malformed one is not displayed (AI-13). */
38
+ function asQuota(value) {
39
+ if (typeof value !== 'object' || value === null) {
40
+ return undefined;
41
+ }
42
+ const candidate = value;
43
+ const fields = [candidate.minuteRemaining, candidate.dayRemaining, candidate.dayTokensRemaining];
44
+ if (!fields.every(field => typeof field === 'number' && Number.isFinite(field))) {
45
+ return undefined;
46
+ }
47
+ return {
48
+ minuteRemaining: candidate.minuteRemaining,
49
+ dayRemaining: candidate.dayRemaining,
50
+ dayTokensRemaining: candidate.dayTokensRemaining
51
+ };
52
+ }
53
+ function createAiClient(clientConfig) {
54
+ const resourceKey = clientConfig.resourceKey ?? 'ai-gateway';
55
+ const transport = clientConfig.transport ?? _sseClient.requestSse;
56
+ const fetchFn = clientConfig.fetchFn ?? fetch;
57
+ const timeouts = {
58
+ ..._timeouts.DEFAULT_AI_TIMEOUTS,
59
+ ...clientConfig.timeouts
60
+ };
61
+ const scheduler = clientConfig.scheduler ?? _rnCore.realScheduler;
62
+ const configManager = new _behaviorConfig.BehaviorConfigManager({
63
+ configUrl: clientConfig.configUrl,
64
+ appId: clientConfig.appId,
65
+ cache: clientConfig.storage,
66
+ fetchFn: clientConfig.fetchFn,
67
+ timeoutMs: timeouts.configMs,
68
+ ...(clientConfig.allowedHosts ? {
69
+ allowedHosts: clientConfig.allowedHosts
70
+ } : {})
71
+ });
72
+ let lastConfig;
73
+ const behaviorListeners = (0, _rnCore.createListenerSet)();
74
+ let snapshot;
75
+ let quota;
76
+
77
+ /** Rebuilt only when a field changes, so useSyncExternalStore sees a stable object. */
78
+ function behaviorState() {
79
+ const config = configManager.state;
80
+ const aiEnabled = lastConfig?.features.aiEnabled ?? true;
81
+ if (!snapshot || snapshot.config !== config || snapshot.aiEnabled !== aiEnabled) {
82
+ snapshot = {
83
+ config,
84
+ aiEnabled
85
+ };
86
+ }
87
+ return snapshot;
88
+ }
89
+ function setLastConfig(next) {
90
+ const wasEnabled = lastConfig?.features.aiEnabled ?? true;
91
+ lastConfig = next;
92
+ if (next.features.aiEnabled !== wasEnabled) behaviorListeners.notify();
93
+ }
94
+
95
+ /** One place records the quota, whichever call learned it (AI-13). */
96
+ function setQuota(next) {
97
+ if (!next || quota && shallowSameQuota(quota, next)) {
98
+ return;
99
+ }
100
+ quota = next;
101
+ behaviorListeners.notify();
102
+ }
103
+ async function acquire(options = {}) {
104
+ const config = await configManager.getConfig();
105
+ setLastConfig(config);
106
+ if (!config.features.aiEnabled) {
107
+ throw new _errors.AiError('config-unavailable', 'AI is disabled for this app', {
108
+ recoverable: false
109
+ });
110
+ }
111
+ const tokenResult = await clientConfig.auth.requestAccessToken(resourceKey, {
112
+ forceRefresh: options.forceRefresh === true
113
+ });
114
+ if (tokenResult.status !== 'success' || !tokenResult.token) {
115
+ // What the auth layer called it, kept as the cause: a screen has to tell
116
+ // "sign in again" from "you are offline" (AI-11).
117
+ throw tokenError(tokenResult.status, tokenResult.errorCode);
118
+ }
119
+ return {
120
+ config,
121
+ token: tokenResult.token
122
+ };
123
+ }
124
+ const endpoint = (config, path) => `${config.api.baseUrl}/api/v1/apps/${clientConfig.appId}/${path}`;
125
+ function chat(request, handlers) {
126
+ let cancelled = false;
127
+ let settled = false;
128
+ let inner;
129
+
130
+ // Every callback to the app goes through here. Nothing is delivered after
131
+ // cancel() — an acquire() or config reload that failed after the user
132
+ // cancelled (or sent the next message) used to flip that screen to
133
+ // `error` — and exactly one terminal callback is delivered.
134
+ const emit = {
135
+ delta(text) {
136
+ if (!cancelled && !settled) handlers.onDelta(text);
137
+ },
138
+ done(result) {
139
+ if (cancelled || settled) return;
140
+ settled = true;
141
+ setQuota(result.quota);
142
+ handlers.onDone(result);
143
+ },
144
+ error(error) {
145
+ if (cancelled || settled) return;
146
+ settled = true;
147
+ inner?.cancel();
148
+ report('chat', error);
149
+ handlers.onError(error);
150
+ }
151
+ };
152
+
153
+ // Any exception on the way becomes a reported error. Each path used to end
154
+ // in `.catch(() => undefined)`, so a transport that threw (a bad URL from
155
+ // remote config, say) left the UI in `loading` with nothing to show.
156
+ const fail = e => emit.error(e instanceof _errors.AiError ? e : new _errors.AiError('internal', e instanceof Error ? e.message : String(e)));
157
+ const guarded = fn => (...args) => {
158
+ try {
159
+ fn(...args);
160
+ } catch (e) {
161
+ fail(e);
162
+ }
163
+ };
164
+ const attempt = async state => {
165
+ const {
166
+ config,
167
+ token
168
+ } = await acquire({
169
+ forceRefresh: state.authRetries > 0
170
+ });
171
+ if (cancelled) return;
172
+ let done;
173
+ let streamErrorCode;
174
+ inner = transport({
175
+ url: endpoint(config, 'chat'),
176
+ method: 'POST',
177
+ headers: {
178
+ Authorization: `Bearer ${token}`,
179
+ 'Content-Type': 'application/json'
180
+ },
181
+ body: JSON.stringify(request),
182
+ connectTimeoutMs: timeouts.connectMs,
183
+ idleTimeoutMs: timeouts.idleMs
184
+ }, {
185
+ onData: guarded(payload => {
186
+ if (payload === _gateway.SSE_DONE_SENTINEL) return;
187
+ let event;
188
+ try {
189
+ event = JSON.parse(payload);
190
+ } catch {
191
+ return;
192
+ }
193
+ if (event.type === 'delta' && typeof event.text === 'string') {
194
+ emit.delta(event.text);
195
+ } else if (event.type === 'done' && event.usage) {
196
+ done = {
197
+ usage: event.usage,
198
+ quota: asQuota(event.quota)
199
+ };
200
+ } else if (event.type === 'error') {
201
+ streamErrorCode = event.code ?? 'UPSTREAM_ERROR';
202
+ }
203
+ }),
204
+ onEnd: guarded(() => {
205
+ if (streamErrorCode) {
206
+ emit.error(new _errors.AiError('upstream-error', 'the AI service failed mid-response', {
207
+ cause: streamErrorCode
208
+ }));
209
+ } else if (done) {
210
+ emit.done(done);
211
+ } else {
212
+ // Headers said 200 and the body stopped short: the connection
213
+ // dropped mid-answer, which is a network failure, not a fault
214
+ // of the service.
215
+ emit.error(new _errors.AiError('network', 'the stream ended before it completed'));
216
+ }
217
+ }),
218
+ onError: guarded((status, bodyText, response) => {
219
+ if (cancelled) return;
220
+ recover(status, bodyText, state, {
221
+ ...(response ? {
222
+ getHeader: name => response.getHeader(name)
223
+ } : {})
224
+ }, next => attempt(next).catch(fail), fail, emit.error);
225
+ })
226
+ });
227
+ };
228
+ attempt({
229
+ configReloads: 0,
230
+ authRetries: 0
231
+ }).catch(fail);
232
+ return {
233
+ cancel() {
234
+ cancelled = true;
235
+ inner?.cancel();
236
+ }
237
+ };
238
+ }
239
+
240
+ /**
241
+ * The two recoveries the contract promises, in one place so chat and quota
242
+ * cannot drift (AI-13): a designated status reloads the configuration and
243
+ * retries after the configured backoff, and a 401 retries once with a token
244
+ * the provider had to fetch again.
245
+ */
246
+ function recover(status, bodyText, state, context, retry, onFailure, onGiveUp) {
247
+ const config = lastConfig;
248
+ if (config && config.recovery.reloadOnHttpStatus.includes(status) && state.configReloads < config.recovery.maxSilentRetries) {
249
+ // Waits `recovery.retryBackoffMs` first (AI-05): a gateway mid-rollout
250
+ // that answered 410 a moment ago may well answer it again at once.
251
+ const retryAfter = backoffBefore(config.recovery.retryBackoffMs, state.configReloads);
252
+ configManager.getConfig({
253
+ forceReload: true
254
+ }).then(reloaded => {
255
+ setLastConfig(reloaded);
256
+ scheduler.setTimeout(() => retry({
257
+ ...state,
258
+ configReloads: state.configReloads + 1
259
+ }), retryAfter);
260
+ }, e => onFailure(e instanceof _errors.AiError ? e : new _errors.AiError('config-unavailable', String(e))));
261
+ return;
262
+ }
263
+ // Expired server-side session → one retry with a token the provider
264
+ // actually re-fetched.
265
+ if (status === 401 && state.authRetries < 1) {
266
+ retry({
267
+ ...state,
268
+ authRetries: state.authRetries + 1
269
+ });
270
+ return;
271
+ }
272
+ onGiveUp((0, _errors.errorFromHttp)(status, bodyText, context));
273
+ }
274
+ const {
275
+ getQuota
276
+ } = (0, _quotaRequest.createQuotaRequest)({
277
+ fetchFn,
278
+ timeouts,
279
+ acquire,
280
+ endpoint,
281
+ asQuota,
282
+ recover,
283
+ report: error => report('quota', error),
284
+ setQuota
285
+ });
286
+ return {
287
+ chat,
288
+ getQuota,
289
+ lastQuota: () => quota,
290
+ getBehaviorState: () => behaviorState(),
291
+ subscribe: listener => {
292
+ const fromManager = configManager.subscribe(listener);
293
+ const fromClient = behaviorListeners.add(listener);
294
+ return () => {
295
+ fromManager();
296
+ fromClient();
297
+ };
298
+ },
299
+ reloadConfig: async () => {
300
+ setLastConfig(await configManager.getConfig({
301
+ forceReload: true
302
+ }));
303
+ }
304
+ };
305
+ }
306
+ function shallowSameQuota(a, b) {
307
+ return a.minuteRemaining === b.minuteRemaining && a.dayRemaining === b.dayRemaining && a.dayTokensRemaining === b.dayTokensRemaining;
308
+ }
309
+
310
+ /**
311
+ * What the auth layer's refusal means for a chat. The code rn-auth gave is kept
312
+ * as the cause, and it decides the copy: "sign in again" and "you are offline"
313
+ * are different answers, and both used to arrive as `auth-invalid` (AI-11).
314
+ */
315
+ function tokenError(status, errorCode) {
316
+ const cause = errorCode ? {
317
+ cause: errorCode
318
+ } : {};
319
+ switch (errorCode) {
320
+ case 'session-expired':
321
+ return new _errors.AiError('session-expired', 'the session ended; sign in again', cause);
322
+ case 'network-unavailable':
323
+ return new _errors.AiError('network', 'no connection to the identity provider', cause);
324
+ case 'consent-denied':
325
+ return new _errors.AiError('not-entitled', 'access to the AI resource was denied', cause);
326
+ default:
327
+ return new _errors.AiError('auth-invalid', status === 'denied' ? 'access to the AI resource was refused' : 'could not acquire an access token', cause);
328
+ }
329
+ }
330
+ //# sourceMappingURL=aiClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_rnCore","require","_behaviorConfig","_gateway","_errors","_sseClient","_quotaRequest","_timeouts","channel","createDiagnosticChannel","report","operation","error","emit","code","retryable","MAX_RETRY_BACKOFF_MS","backoffBefore","steps","index","step","Math","min","length","max","asQuota","value","undefined","candidate","fields","minuteRemaining","dayRemaining","dayTokensRemaining","every","field","Number","isFinite","createAiClient","clientConfig","resourceKey","transport","requestSse","fetchFn","fetch","timeouts","DEFAULT_AI_TIMEOUTS","scheduler","realScheduler","configManager","BehaviorConfigManager","configUrl","appId","cache","storage","timeoutMs","configMs","allowedHosts","lastConfig","behaviorListeners","createListenerSet","snapshot","quota","behaviorState","config","state","aiEnabled","features","setLastConfig","next","wasEnabled","notify","setQuota","shallowSameQuota","acquire","options","getConfig","AiError","recoverable","tokenResult","auth","requestAccessToken","forceRefresh","status","token","tokenError","errorCode","endpoint","path","api","baseUrl","chat","request","handlers","cancelled","settled","inner","delta","text","onDelta","done","result","onDone","cancel","onError","fail","e","Error","message","String","guarded","fn","args","attempt","authRetries","streamErrorCode","url","method","headers","Authorization","body","JSON","stringify","connectTimeoutMs","connectMs","idleTimeoutMs","idleMs","onData","payload","SSE_DONE_SENTINEL","event","parse","type","usage","onEnd","cause","bodyText","response","recover","getHeader","name","catch","configReloads","context","retry","onFailure","onGiveUp","recovery","reloadOnHttpStatus","includes","maxSilentRetries","retryAfter","retryBackoffMs","forceReload","then","reloaded","setTimeout","errorFromHttp","getQuota","createQuotaRequest","lastQuota","getBehaviorState","subscribe","listener","fromManager","fromClient","add","reloadConfig","a","b"],"sourceRoot":"../../../src","sources":["core/aiClient.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,105 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.createQuotaRequest = createQuotaRequest;
7
+ var _errors = require("../diagnostics/errors.js");
8
+ var _timeouts = require("../transport/timeouts.js");
9
+ /**
10
+ * The quota request, and the recovery it shares with a chat (AI-13).
11
+ *
12
+ * `getQuota` used to be the one call with no recovery at all: a gateway that
13
+ * had moved answered 404 for quota while chats silently re-routed, so the
14
+ * figure on screen failed while the feature worked. It now goes through the
15
+ * same `recover` the chat stream does — a designated status reloads the
16
+ * configuration and retries, a 401 retries once with a token the provider had
17
+ * to fetch again.
18
+ */
19
+
20
+ /** Where the quota request is in its recovery, shared with the chat path. */
21
+
22
+ /** What is left of the app's allowance. */
23
+
24
+ function createQuotaRequest(deps) {
25
+ const {
26
+ fetchFn,
27
+ timeouts,
28
+ endpoint,
29
+ asQuota,
30
+ recover,
31
+ setQuota
32
+ } = deps;
33
+ const acquire = deps.acquire;
34
+ async function getQuota() {
35
+ try {
36
+ const snapshotValue = await fetchQuotaWithRecovery({
37
+ configReloads: 0,
38
+ authRetries: 0
39
+ });
40
+ setQuota(snapshotValue);
41
+ return snapshotValue;
42
+ } catch (error) {
43
+ if (error instanceof _errors.AiError) deps.report(error);
44
+ throw error;
45
+ }
46
+ }
47
+
48
+ /** Same recovery as a chat: a retired endpoint reloads the config and retries. */
49
+ function fetchQuotaWithRecovery(state) {
50
+ return new Promise((resolve, reject) => {
51
+ fetchQuota(state).then(resolve, error => {
52
+ if (!(error instanceof HttpFailure)) {
53
+ reject(error);
54
+ return;
55
+ }
56
+ recover(error.status, error.bodyText, state, {
57
+ getHeader: name => error.getHeader(name)
58
+ }, next => fetchQuotaWithRecovery(next).then(resolve, reject), reject, reject);
59
+ });
60
+ });
61
+ }
62
+
63
+ /** Carries the response so `recover` can decide; never reaches the caller. */
64
+ class HttpFailure extends Error {
65
+ constructor(status, bodyText, headers) {
66
+ super(`gateway responded ${status}`);
67
+ this.status = status;
68
+ this.bodyText = bodyText;
69
+ this.headers = headers;
70
+ this.name = 'HttpFailure';
71
+ }
72
+ getHeader(name) {
73
+ return this.headers?.get(name) ?? null;
74
+ }
75
+ }
76
+ async function fetchQuota(state) {
77
+ const {
78
+ config,
79
+ token
80
+ } = await acquire({
81
+ forceRefresh: state.authRetries > 0
82
+ });
83
+ return (0, _timeouts.withTimeout)(timeouts.quotaMs, async signal => {
84
+ const response = await fetchFn(endpoint(config, 'quota'), {
85
+ headers: {
86
+ Authorization: `Bearer ${token}`
87
+ },
88
+ signal
89
+ });
90
+ if (!response.ok) {
91
+ throw new HttpFailure(response.status, await response.text(), response.headers);
92
+ }
93
+ const parsed = asQuota(await response.json());
94
+ if (!parsed) {
95
+ // A body that is not the contract's: better no figure than a wrong one.
96
+ throw new _errors.AiError('internal', 'quota response did not match the contract');
97
+ }
98
+ return parsed;
99
+ }, () => new _errors.AiError('network', 'quota request timed out'));
100
+ }
101
+ return {
102
+ getQuota
103
+ };
104
+ }
105
+ //# sourceMappingURL=quotaRequest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_errors","require","_timeouts","createQuotaRequest","deps","fetchFn","timeouts","endpoint","asQuota","recover","setQuota","acquire","getQuota","snapshotValue","fetchQuotaWithRecovery","configReloads","authRetries","error","AiError","report","state","Promise","resolve","reject","fetchQuota","then","HttpFailure","status","bodyText","getHeader","name","next","Error","constructor","headers","get","config","token","forceRefresh","withTimeout","quotaMs","signal","response","Authorization","ok","text","parsed","json"],"sourceRoot":"../../../src","sources":["core/quotaRequest.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.AiError = void 0;
7
+ exports.errorFromHttp = errorFromHttp;
8
+ exports.isAiError = isAiError;
9
+ exports.parseRetryAfter = parseRetryAfter;
10
+ var _rnCore = require("@chipmobilesdk/rn-core");
11
+ var _gateway = require("../contract/gateway.js");
12
+ /** Typed client errors (contracts/rn-ai-public-api.md). */
13
+
14
+ /** Codes a retry can fix on its own. */
15
+ const RETRYABLE_BY_DEFAULT = new Set(['rate-limited', 'upstream-busy', 'network']);
16
+
17
+ /** The package's error; an `SdkError` (`@chipmobilesdk/rn-core`) with `pkg: 'rn-ai'`. */
18
+ class AiError extends _rnCore.SdkError {
19
+ /** The underlying code, when one layer down had a name for the failure. */
20
+
21
+ constructor(code, message, options = {}) {
22
+ super('rn-ai', code, {
23
+ message,
24
+ retryable: options.retryable ?? options.recoverable ?? RETRYABLE_BY_DEFAULT.has(code)
25
+ });
26
+ this.name = 'AiError';
27
+ this.retryAfterSeconds = options.retryAfterSeconds;
28
+ this.cause = options.cause;
29
+ }
30
+
31
+ /** @deprecated Use `retryable`, the name every SDK package shares. */
32
+ get recoverable() {
33
+ return this.retryable;
34
+ }
35
+ }
36
+ exports.AiError = AiError;
37
+ function isAiError(value) {
38
+ return value instanceof AiError;
39
+ }
40
+
41
+ /**
42
+ * Every gateway code, mapped. Typed as a total record, so a code added to the
43
+ * shared contract does not compile until the client says what it means (GW-13).
44
+ */
45
+ const HTTP_CODE_MAP = {
46
+ BAD_REQUEST: 'internal',
47
+ AUTH_INVALID: 'auth-invalid',
48
+ NOT_ENTITLED: 'not-entitled',
49
+ USER_BLOCKED: 'user-blocked',
50
+ APP_UNKNOWN: 'app-unknown',
51
+ // The endpoint moved: the client's configuration is the stale part.
52
+ ENDPOINT_RETIRED: 'config-unavailable',
53
+ PAYLOAD_TOO_LARGE: 'payload-too-large',
54
+ MODALITY_NOT_ALLOWED: 'modality-not-allowed',
55
+ RATE_LIMITED: 'rate-limited',
56
+ UPSTREAM_BUSY: 'upstream-busy',
57
+ UPSTREAM_ERROR: 'upstream-error',
58
+ INTERNAL: 'internal'
59
+ };
60
+ function isGatewayCode(value) {
61
+ return typeof value === 'string' && value in HTTP_CODE_MAP;
62
+ }
63
+
64
+ /** `Retry-After` in seconds, from either form the header may take. */
65
+ function parseRetryAfter(value) {
66
+ if (!value) {
67
+ return undefined;
68
+ }
69
+ const seconds = Number(value);
70
+ if (Number.isFinite(seconds) && seconds >= 0) {
71
+ return seconds;
72
+ }
73
+ const date = Date.parse(value);
74
+ if (Number.isFinite(date)) {
75
+ return Math.max(0, Math.round((date - Date.now()) / 1000));
76
+ }
77
+ return undefined;
78
+ }
79
+ /** Map a gateway error response (status + JSON body) to a typed AiError. */
80
+ function errorFromHttp(status, bodyText, context = {}) {
81
+ // Status 0 is not an answer at all: the request never arrived, or the
82
+ // connection dropped. That is a network failure a retry may well fix, not an
83
+ // upstream fault (AI-11).
84
+ if (status === 0) {
85
+ return new AiError('network', bodyText === 'timeout' ? 'the request timed out' : 'no connection');
86
+ }
87
+ let code = status >= 500 ? 'upstream-error' : 'internal';
88
+ let message = `gateway responded ${status}`;
89
+ let gatewayCode;
90
+ let retryAfterSeconds = parseRetryAfter(context.getHeader?.(_gateway.RETRY_AFTER_HEADER));
91
+ try {
92
+ const parsed = JSON.parse(bodyText);
93
+ if (isGatewayCode(parsed.error?.code)) {
94
+ gatewayCode = parsed.error.code;
95
+ code = HTTP_CODE_MAP[gatewayCode];
96
+ }
97
+ // The gateway's text can quote upstream detail; keep it readable but shaped.
98
+ if (parsed.error?.message) message = (0, _rnCore.redactPatterns)(parsed.error.message);
99
+ retryAfterSeconds = parsed.error?.retryAfterSeconds ?? retryAfterSeconds;
100
+ } catch {
101
+ // A body that is not the contract's: the status is all there is to go on.
102
+ }
103
+ return new AiError(code, message, {
104
+ retryAfterSeconds,
105
+ cause: gatewayCode
106
+ });
107
+ }
108
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_rnCore","require","_gateway","RETRYABLE_BY_DEFAULT","Set","AiError","SdkError","constructor","code","message","options","retryable","recoverable","has","name","retryAfterSeconds","cause","exports","isAiError","value","HTTP_CODE_MAP","BAD_REQUEST","AUTH_INVALID","NOT_ENTITLED","USER_BLOCKED","APP_UNKNOWN","ENDPOINT_RETIRED","PAYLOAD_TOO_LARGE","MODALITY_NOT_ALLOWED","RATE_LIMITED","UPSTREAM_BUSY","UPSTREAM_ERROR","INTERNAL","isGatewayCode","parseRetryAfter","undefined","seconds","Number","isFinite","date","Date","parse","Math","max","round","now","errorFromHttp","status","bodyText","context","gatewayCode","getHeader","RETRY_AFTER_HEADER","parsed","JSON","error","redactPatterns"],"sourceRoot":"../../../src","sources":["diagnostics/errors.ts"],"mappings":"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","ignoreList":[]}