@qafka/react-native 2.4.0 → 2.4.2
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/CHANGELOG.md +12 -0
- package/dist/QafkaSDK.js +2 -1
- package/dist/components/Qafka.js +19 -4
- package/dist/components/Qafka.types.d.ts +5 -4
- package/dist/constants.d.ts +10 -0
- package/dist/constants.js +11 -1
- package/dist/index.d.ts +0 -1
- package/dist/services/BackendService.js +18 -3
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,18 @@ and this project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.ht
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [2.4.2] — 2026-06-22
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- Voice could fail to connect (the orb stayed on the connecting/waiting state) in apps that did not pass an explicit `apiUrl`. The realtime WebSocket now falls back to the same default backend host as the REST/chat client, instead of building a host-less relative URL that could never complete its handshake. Apps relying on the default backend no longer need to set `apiUrl` just to make voice work.
|
|
15
|
+
|
|
16
|
+
## [2.4.1] — 2026-06-21
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- Development experience: when a development (test) API key has been rotated and the app is still running the old key, chat no longer fails silently. In development builds the SDK now logs an actionable warning and shows an in-chat message telling the developer to run `qafka refresh` and restart Metro with `--clear`. This guidance is stripped from release builds (`__DEV__`-gated) and only triggers for development keys, so it can never appear in production.
|
|
21
|
+
|
|
10
22
|
## [2.4.0] — 2026-06-21
|
|
11
23
|
|
|
12
24
|
### Added
|
package/dist/QafkaSDK.js
CHANGED
|
@@ -6,6 +6,7 @@ const BackendService_1 = require("./services/BackendService");
|
|
|
6
6
|
const AttestationManager_1 = require("./services/AttestationManager");
|
|
7
7
|
const ConversationManager_1 = require("./services/ConversationManager");
|
|
8
8
|
const NavigationHandler_1 = require("./services/NavigationHandler");
|
|
9
|
+
const constants_1 = require("./constants");
|
|
9
10
|
/**
|
|
10
11
|
* QafkaSDK - Main SDK class
|
|
11
12
|
* Provides AI-powered conversational interface for React Native apps
|
|
@@ -85,7 +86,7 @@ class QafkaSDK {
|
|
|
85
86
|
await this.conversationManager.initialize();
|
|
86
87
|
this.navigationHandler = new NavigationHandler_1.NavigationHandler(config.navigationRef);
|
|
87
88
|
// Initialize device attestation
|
|
88
|
-
const rawUrl = (config.apiUrl ||
|
|
89
|
+
const rawUrl = (config.apiUrl || `${constants_1.DEFAULT_API_BASE}/api/v1`).replace(/\/$/, '');
|
|
89
90
|
const attestApiUrl = rawUrl.includes('/api/v1') ? rawUrl : `${rawUrl}/api/v1`;
|
|
90
91
|
this.attestationManager = new AttestationManager_1.AttestationManager({
|
|
91
92
|
apiUrl: attestApiUrl,
|
package/dist/components/Qafka.js
CHANGED
|
@@ -49,6 +49,7 @@ const validate_end_user_1 = require("../validate-end-user");
|
|
|
49
49
|
const ChatPage_1 = require("./ChatPage");
|
|
50
50
|
const VoicePage_1 = require("./VoicePage");
|
|
51
51
|
const useVoiceChat_1 = require("../hooks/useVoiceChat");
|
|
52
|
+
const constants_1 = require("../constants");
|
|
52
53
|
const { width: SCREEN_WIDTH } = react_native_1.Dimensions.get('window');
|
|
53
54
|
/**
|
|
54
55
|
* Qafka Component
|
|
@@ -126,10 +127,10 @@ exports.Qafka = (0, react_1.forwardRef)(function Qafka({ style, apiUrl: apiUrlPr
|
|
|
126
127
|
debounceMs: 500,
|
|
127
128
|
});
|
|
128
129
|
const voiceChat = (0, useVoiceChat_1.useVoiceChat)({
|
|
129
|
-
// Voice WebSocket
|
|
130
|
-
//
|
|
131
|
-
//
|
|
132
|
-
apiUrl: resolvedApiUrl || apiUrlProp ||
|
|
130
|
+
// Voice realtime WebSocket. Fall back to the shared default backend host so
|
|
131
|
+
// the WS URL never resolves host-less (an empty apiUrl produced a relative
|
|
132
|
+
// `/v1/realtime` URL → handshake failure). Mirrors the REST client default.
|
|
133
|
+
apiUrl: resolvedApiUrl || apiUrlProp || constants_1.DEFAULT_API_BASE,
|
|
133
134
|
apiKey: resolvedApiKey || '',
|
|
134
135
|
userContext: currentContext,
|
|
135
136
|
contextDescription,
|
|
@@ -311,6 +312,20 @@ exports.Qafka = (0, react_1.forwardRef)(function Qafka({ style, apiUrl: apiUrlPr
|
|
|
311
312
|
setIsInitialMessageLoading(false);
|
|
312
313
|
if (__DEV__) {
|
|
313
314
|
console.warn('[Qafka] Initial message error:', err.message);
|
|
315
|
+
// Dev-only: a stale rotated test key would otherwise fail silently.
|
|
316
|
+
// Surface the actionable hint in the transcript so it is visible.
|
|
317
|
+
const devErr = err;
|
|
318
|
+
if (devErr.code === 'DEV_KEY_INVALID') {
|
|
319
|
+
const devErrMsg = {
|
|
320
|
+
id: `dev-key-error-${Date.now()}`,
|
|
321
|
+
role: 'assistant',
|
|
322
|
+
text: err.message,
|
|
323
|
+
content: err.message,
|
|
324
|
+
timestamp: new Date(),
|
|
325
|
+
metadata: { isInitialMessage: true },
|
|
326
|
+
};
|
|
327
|
+
setMessages((prev) => [...prev, devErrMsg]);
|
|
328
|
+
}
|
|
314
329
|
}
|
|
315
330
|
}, currentContext, contextDescription, undefined, // onToolSuggestions
|
|
316
331
|
true);
|
|
@@ -8,10 +8,11 @@ import type { RuntimeConfig } from '../runtime-config-loader';
|
|
|
8
8
|
/**
|
|
9
9
|
* Augmentation hook for consumer-side projectId literal types.
|
|
10
10
|
*
|
|
11
|
-
* The Qafka CLI generates a `qafka.config.d.ts` file
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
11
|
+
* The Qafka CLI generates a `qafka.config.d.ts` file at the consumer
|
|
12
|
+
* project root whenever it writes the runtime config; the consumer's
|
|
13
|
+
* tsconfig file scan picks it up. That `.d.ts` augments this interface
|
|
14
|
+
* with the consumer's project ids as keys — giving
|
|
15
|
+
* `<Qafka projectId="..." />` autocomplete + typo validation.
|
|
15
16
|
*
|
|
16
17
|
* When the augmentation is absent (fresh project, `qafka init` not yet
|
|
17
18
|
* run), `keyof QafkaProjectIds` is `never` and `ProjectIdOf` falls back
|
package/dist/constants.d.ts
CHANGED
|
@@ -3,6 +3,16 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export declare const API_VERSION = "v1";
|
|
5
5
|
export declare const DEFAULT_API_TIMEOUT = 30000;
|
|
6
|
+
/**
|
|
7
|
+
* Default Qafka backend base host (scheme + host only).
|
|
8
|
+
*
|
|
9
|
+
* The REST client appends `/api/v1` and the realtime voice client appends
|
|
10
|
+
* `/v1/realtime`, so this holds the bare base. Used as the fallback when neither
|
|
11
|
+
* an explicit `apiUrl` prop nor a runtime-config `apiUrl` is provided — keeps the
|
|
12
|
+
* REST and voice transports pointed at the same host instead of one silently
|
|
13
|
+
* defaulting while the other resolves to an empty (host-less) URL.
|
|
14
|
+
*/
|
|
15
|
+
export declare const DEFAULT_API_BASE = "https://api.qafka.com";
|
|
6
16
|
export declare const STORAGE_KEYS: {
|
|
7
17
|
readonly CONFIG: "@qafka/config";
|
|
8
18
|
readonly CONVERSATION_HISTORY: "@qafka/conversation_history";
|
package/dist/constants.js
CHANGED
|
@@ -3,9 +3,19 @@
|
|
|
3
3
|
* Shared constants for SDK
|
|
4
4
|
*/
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.STORAGE_KEYS = exports.DEFAULT_API_TIMEOUT = exports.API_VERSION = void 0;
|
|
6
|
+
exports.STORAGE_KEYS = exports.DEFAULT_API_BASE = exports.DEFAULT_API_TIMEOUT = exports.API_VERSION = void 0;
|
|
7
7
|
exports.API_VERSION = 'v1';
|
|
8
8
|
exports.DEFAULT_API_TIMEOUT = 30000;
|
|
9
|
+
/**
|
|
10
|
+
* Default Qafka backend base host (scheme + host only).
|
|
11
|
+
*
|
|
12
|
+
* The REST client appends `/api/v1` and the realtime voice client appends
|
|
13
|
+
* `/v1/realtime`, so this holds the bare base. Used as the fallback when neither
|
|
14
|
+
* an explicit `apiUrl` prop nor a runtime-config `apiUrl` is provided — keeps the
|
|
15
|
+
* REST and voice transports pointed at the same host instead of one silently
|
|
16
|
+
* defaulting while the other resolves to an empty (host-less) URL.
|
|
17
|
+
*/
|
|
18
|
+
exports.DEFAULT_API_BASE = 'https://api.qafka.com';
|
|
9
19
|
exports.STORAGE_KEYS = {
|
|
10
20
|
CONFIG: '@qafka/config',
|
|
11
21
|
CONVERSATION_HISTORY: '@qafka/conversation_history',
|
package/dist/index.d.ts
CHANGED
|
@@ -601,12 +601,27 @@ class BackendService {
|
|
|
601
601
|
});
|
|
602
602
|
}
|
|
603
603
|
else {
|
|
604
|
+
let serverMessage;
|
|
604
605
|
try {
|
|
605
|
-
|
|
606
|
-
onError(new Error(errorData.message || `HTTP Error: ${xhr.status}`));
|
|
606
|
+
serverMessage = JSON.parse(xhr.responseText)?.message;
|
|
607
607
|
}
|
|
608
608
|
catch {
|
|
609
|
-
|
|
609
|
+
// non-JSON error body; fall through to a status-based message
|
|
610
|
+
}
|
|
611
|
+
// In dev, a 401 with a test key almost always means the rotated dev
|
|
612
|
+
// key is stale. Surface an actionable hint instead of a bare HTTP error.
|
|
613
|
+
if (__DEV__ && xhr.status === 401 && this.apiKey?.startsWith('qafka_test_')) {
|
|
614
|
+
const hint = 'Qafka dev key is invalid or was rotated. Run `qafka refresh`, then restart Metro with --clear.';
|
|
615
|
+
console.warn(`[Qafka] ${hint}`);
|
|
616
|
+
const devErr = new Error(hint);
|
|
617
|
+
devErr.code = 'DEV_KEY_INVALID';
|
|
618
|
+
devErr.status = xhr.status;
|
|
619
|
+
onError(devErr);
|
|
620
|
+
}
|
|
621
|
+
else {
|
|
622
|
+
const httpErr = new Error(serverMessage || `HTTP Error: ${xhr.status}`);
|
|
623
|
+
httpErr.status = xhr.status;
|
|
624
|
+
onError(httpErr);
|
|
610
625
|
}
|
|
611
626
|
}
|
|
612
627
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qafka/react-native",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.2",
|
|
4
4
|
"description": "Drop-in AI assistant for React Native: chat, voice, and tool execution with screen-aware navigation.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"LICENSE"
|
|
24
24
|
],
|
|
25
25
|
"scripts": {
|
|
26
|
-
"build": "tsc
|
|
26
|
+
"build": "tsc",
|
|
27
27
|
"dev": "tsc --watch",
|
|
28
28
|
"clean": "rm -rf dist",
|
|
29
29
|
"typecheck": "tsc --noEmit",
|