react-native-newinstance-chat 0.1.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.
- package/LICENSE +20 -0
- package/NewinstanceChat.podspec +23 -0
- package/README.md +106 -0
- package/android/build.gradle +79 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/com/newinstancechat/NewinstanceChatModule.kt +200 -0
- package/android/src/main/java/com/newinstancechat/NewinstanceChatPackage.kt +31 -0
- package/ios/NewinstanceChat.h +12 -0
- package/ios/NewinstanceChat.mm +103 -0
- package/ios/NewinstanceChatImpl.swift +239 -0
- package/lib/module/NativeNewinstanceChat.js +17 -0
- package/lib/module/NativeNewinstanceChat.js.map +1 -0
- package/lib/module/index.js +88 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/types.js +2 -0
- package/lib/module/types.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/NativeNewinstanceChat.d.ts +27 -0
- package/lib/typescript/src/NativeNewinstanceChat.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +52 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/types.d.ts +69 -0
- package/lib/typescript/src/types.d.ts.map +1 -0
- package/package.json +166 -0
- package/src/NativeNewinstanceChat.ts +30 -0
- package/src/index.tsx +120 -0
- package/src/types.ts +86 -0
package/package.json
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "react-native-newinstance-chat",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "New instance LiveAndAiChat React Native SDK — AI + live-agent chat, drop-in native chat screen for iOS and Android.",
|
|
5
|
+
"main": "./lib/module/index.js",
|
|
6
|
+
"types": "./lib/typescript/src/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"source": "./src/index.tsx",
|
|
10
|
+
"types": "./lib/typescript/src/index.d.ts",
|
|
11
|
+
"default": "./lib/module/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./package.json": "./package.json"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"src",
|
|
17
|
+
"lib",
|
|
18
|
+
"android",
|
|
19
|
+
"ios",
|
|
20
|
+
"cpp",
|
|
21
|
+
"*.podspec",
|
|
22
|
+
"react-native.config.js",
|
|
23
|
+
"!ios/build",
|
|
24
|
+
"!android/build",
|
|
25
|
+
"!android/gradle",
|
|
26
|
+
"!android/gradlew",
|
|
27
|
+
"!android/gradlew.bat",
|
|
28
|
+
"!android/local.properties",
|
|
29
|
+
"!**/__tests__",
|
|
30
|
+
"!**/__fixtures__",
|
|
31
|
+
"!**/__mocks__",
|
|
32
|
+
"!**/.*"
|
|
33
|
+
],
|
|
34
|
+
"scripts": {
|
|
35
|
+
"example": "yarn workspace react-native-newinstance-chat-example",
|
|
36
|
+
"clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib",
|
|
37
|
+
"prepare": "bob build",
|
|
38
|
+
"typecheck": "tsc",
|
|
39
|
+
"lint": "eslint \"**/*.{js,ts,tsx}\"",
|
|
40
|
+
"test": "jest",
|
|
41
|
+
"release": "release-it --only-version",
|
|
42
|
+
"web": "vite",
|
|
43
|
+
"build:web": "vite build"
|
|
44
|
+
},
|
|
45
|
+
"keywords": [
|
|
46
|
+
"react-native",
|
|
47
|
+
"ios",
|
|
48
|
+
"android"
|
|
49
|
+
],
|
|
50
|
+
"repository": {
|
|
51
|
+
"type": "git",
|
|
52
|
+
"url": "git+https://github.com/talktothelaw/react-native-newinstance-chat.git"
|
|
53
|
+
},
|
|
54
|
+
"author": "lawrence <nwokolawrence6@gmail.com> (https://github.com/talktothelaw)",
|
|
55
|
+
"license": "MIT",
|
|
56
|
+
"bugs": {
|
|
57
|
+
"url": "https://github.com/talktothelaw/react-native-newinstance-chat/issues"
|
|
58
|
+
},
|
|
59
|
+
"homepage": "https://github.com/talktothelaw/react-native-newinstance-chat#readme",
|
|
60
|
+
"publishConfig": {
|
|
61
|
+
"registry": "https://registry.npmjs.org/"
|
|
62
|
+
},
|
|
63
|
+
"devDependencies": {
|
|
64
|
+
"@eslint/compat": "^2.0.3",
|
|
65
|
+
"@eslint/eslintrc": "^3.3.5",
|
|
66
|
+
"@eslint/js": "^10.0.1",
|
|
67
|
+
"@jest/globals": "^30.0.0",
|
|
68
|
+
"@react-native/babel-preset": "0.85.0",
|
|
69
|
+
"@react-native/eslint-config": "0.85.0",
|
|
70
|
+
"@react-native/jest-preset": "0.85.0",
|
|
71
|
+
"@release-it/conventional-changelog": "^10.0.6",
|
|
72
|
+
"@types/react": "^19.2.0",
|
|
73
|
+
"del-cli": "^7.0.0",
|
|
74
|
+
"eslint": "^9.39.4",
|
|
75
|
+
"eslint-config-prettier": "^10.1.8",
|
|
76
|
+
"eslint-plugin-ft-flow": "^3.0.11",
|
|
77
|
+
"eslint-plugin-prettier": "^5.5.5",
|
|
78
|
+
"jest": "^30.3.0",
|
|
79
|
+
"prettier": "^3.8.1",
|
|
80
|
+
"react": "19.2.3",
|
|
81
|
+
"react-native": "0.85.0",
|
|
82
|
+
"react-native-builder-bob": "^0.41.0",
|
|
83
|
+
"react-native-web": "~0.21.1",
|
|
84
|
+
"release-it": "^19.2.4",
|
|
85
|
+
"turbo": "^2.8.21",
|
|
86
|
+
"typescript": "^6.0.2"
|
|
87
|
+
},
|
|
88
|
+
"peerDependencies": {
|
|
89
|
+
"react": "*",
|
|
90
|
+
"react-native": "*"
|
|
91
|
+
},
|
|
92
|
+
"workspaces": [
|
|
93
|
+
"example"
|
|
94
|
+
],
|
|
95
|
+
"packageManager": "yarn@4.11.0",
|
|
96
|
+
"react-native-builder-bob": {
|
|
97
|
+
"source": "src",
|
|
98
|
+
"output": "lib",
|
|
99
|
+
"targets": [
|
|
100
|
+
[
|
|
101
|
+
"module",
|
|
102
|
+
{
|
|
103
|
+
"esm": true
|
|
104
|
+
}
|
|
105
|
+
],
|
|
106
|
+
[
|
|
107
|
+
"typescript",
|
|
108
|
+
{
|
|
109
|
+
"project": "tsconfig.build.json"
|
|
110
|
+
}
|
|
111
|
+
]
|
|
112
|
+
]
|
|
113
|
+
},
|
|
114
|
+
"codegenConfig": {
|
|
115
|
+
"name": "NewinstanceChatSpec",
|
|
116
|
+
"type": "modules",
|
|
117
|
+
"jsSrcsDir": "src",
|
|
118
|
+
"android": {
|
|
119
|
+
"javaPackageName": "com.newinstancechat"
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
"prettier": {
|
|
123
|
+
"quoteProps": "consistent",
|
|
124
|
+
"singleQuote": true,
|
|
125
|
+
"tabWidth": 2,
|
|
126
|
+
"trailingComma": "es5",
|
|
127
|
+
"useTabs": false
|
|
128
|
+
},
|
|
129
|
+
"jest": {
|
|
130
|
+
"preset": "@react-native/jest-preset",
|
|
131
|
+
"modulePathIgnorePatterns": [
|
|
132
|
+
"<rootDir>/example/node_modules",
|
|
133
|
+
"<rootDir>/lib/"
|
|
134
|
+
]
|
|
135
|
+
},
|
|
136
|
+
"release-it": {
|
|
137
|
+
"git": {
|
|
138
|
+
"commitMessage": "chore: release ${version}",
|
|
139
|
+
"tagName": "v${version}"
|
|
140
|
+
},
|
|
141
|
+
"npm": {
|
|
142
|
+
"publish": true
|
|
143
|
+
},
|
|
144
|
+
"github": {
|
|
145
|
+
"release": true
|
|
146
|
+
},
|
|
147
|
+
"plugins": {
|
|
148
|
+
"@release-it/conventional-changelog": {
|
|
149
|
+
"preset": {
|
|
150
|
+
"name": "angular"
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
"create-react-native-library": {
|
|
156
|
+
"type": "turbo-module",
|
|
157
|
+
"languages": "kotlin-objc",
|
|
158
|
+
"tools": [
|
|
159
|
+
"eslint",
|
|
160
|
+
"jest",
|
|
161
|
+
"release-it",
|
|
162
|
+
"vite"
|
|
163
|
+
],
|
|
164
|
+
"version": "0.62.0"
|
|
165
|
+
}
|
|
166
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { TurboModuleRegistry, type TurboModule } from 'react-native';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* TurboModule spec for the LiveAndAiChat React Native bridge. Codegen
|
|
5
|
+
* produces native protocol stubs from this file:
|
|
6
|
+
* - iOS: ios/build/.../NewinstanceChatSpec/NewinstanceChatSpec.h
|
|
7
|
+
* - Android: android/build/.../NativeNewinstanceChatSpec.java
|
|
8
|
+
*
|
|
9
|
+
* Dict-shaped arguments use `Object` because Codegen can't enforce
|
|
10
|
+
* deep object schemas; the JS class enforces the shapes via TypeScript
|
|
11
|
+
* before calling in.
|
|
12
|
+
*/
|
|
13
|
+
export interface Spec extends TurboModule {
|
|
14
|
+
configure(config: Object): Promise<void>;
|
|
15
|
+
setUser(user: Object): void;
|
|
16
|
+
initialize(): Promise<void>;
|
|
17
|
+
openChat(): void;
|
|
18
|
+
closeChat(): void;
|
|
19
|
+
sendMessage(text: string): void;
|
|
20
|
+
retryMessage(messageId: string): void;
|
|
21
|
+
attachFile(opts: Object): Promise<void>;
|
|
22
|
+
destroy(): void;
|
|
23
|
+
|
|
24
|
+
// NativeEventEmitter on iOS calls these to track listener counts.
|
|
25
|
+
// Required even though native emit goes via RCTDeviceEventEmitter.
|
|
26
|
+
addListener(eventName: string): void;
|
|
27
|
+
removeListeners(count: number): void;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default TurboModuleRegistry.getEnforcing<Spec>('NewinstanceChat');
|
package/src/index.tsx
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import {
|
|
2
|
+
NativeEventEmitter,
|
|
3
|
+
NativeModules,
|
|
4
|
+
type EmitterSubscription,
|
|
5
|
+
} from 'react-native';
|
|
6
|
+
|
|
7
|
+
import NativeNewinstanceChat from './NativeNewinstanceChat';
|
|
8
|
+
import type {
|
|
9
|
+
AttachmentInput,
|
|
10
|
+
ChatUser,
|
|
11
|
+
EventHandler,
|
|
12
|
+
EventName,
|
|
13
|
+
NewinstanceChatConfig,
|
|
14
|
+
} from './types';
|
|
15
|
+
|
|
16
|
+
export type {
|
|
17
|
+
AttachmentInput,
|
|
18
|
+
ChatMessage,
|
|
19
|
+
ChatUser,
|
|
20
|
+
ConnectionState,
|
|
21
|
+
EventMap,
|
|
22
|
+
EventName,
|
|
23
|
+
NewinstanceChatConfig,
|
|
24
|
+
NewinstanceChatError,
|
|
25
|
+
NewinstanceChatErrorType,
|
|
26
|
+
} from './types';
|
|
27
|
+
|
|
28
|
+
// Bridge mode (old arch) exposes the module on NativeModules; new arch
|
|
29
|
+
// goes through TurboModuleRegistry. NativeEventEmitter accepts either —
|
|
30
|
+
// we feed it the legacy handle so listener counts get tracked.
|
|
31
|
+
const emitterSource: any =
|
|
32
|
+
NativeModules.NewinstanceChat ?? (NativeNewinstanceChat as unknown);
|
|
33
|
+
const emitter = new NativeEventEmitter(emitterSource);
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* React Native binding for the native LiveAndAiChat iOS / Android SDKs.
|
|
37
|
+
*
|
|
38
|
+
* Construct, optionally set a user, call `initialize()`, then `openChat()`
|
|
39
|
+
* when the host wants to surface the native chat screen. Subscribe to
|
|
40
|
+
* events with `addListener` — the returned function unsubscribes.
|
|
41
|
+
*
|
|
42
|
+
* Multiple `new NewinstanceChat(...)` calls reconfigure the same underlying
|
|
43
|
+
* native instance — the most recent `configure` wins.
|
|
44
|
+
*/
|
|
45
|
+
export class NewinstanceChat {
|
|
46
|
+
/** Resolves once the native SDK is configured. */
|
|
47
|
+
readonly ready: Promise<void>;
|
|
48
|
+
|
|
49
|
+
constructor(config: NewinstanceChatConfig) {
|
|
50
|
+
this.ready = NativeNewinstanceChat.configure(config);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Identify the customer. Safe to call before or after `initialize()`. If
|
|
55
|
+
* called before `configure()` resolves, the user is queued and applied
|
|
56
|
+
* once the native instance exists.
|
|
57
|
+
*/
|
|
58
|
+
setUser(user: ChatUser): void {
|
|
59
|
+
NativeNewinstanceChat.setUser(user);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Fetch org config, restore the saved conversation, and connect the
|
|
64
|
+
* subscription transport in the background. Concurrent callers share
|
|
65
|
+
* the same in-flight init.
|
|
66
|
+
*/
|
|
67
|
+
initialize(): Promise<void> {
|
|
68
|
+
return NativeNewinstanceChat.initialize();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Present the native chat screen modally over the current RN host. */
|
|
72
|
+
openChat(): void {
|
|
73
|
+
NativeNewinstanceChat.openChat();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Dismiss the native chat screen. */
|
|
77
|
+
closeChat(): void {
|
|
78
|
+
NativeNewinstanceChat.closeChat();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
sendMessage(text: string): void {
|
|
82
|
+
NativeNewinstanceChat.sendMessage(text);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
retryMessage(messageId: string): void {
|
|
86
|
+
NativeNewinstanceChat.retryMessage(messageId);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Queue a local file as an attachment. The native side reads bytes from
|
|
91
|
+
* `uri`, pushes them through the SDK's upload pipeline, and bundles the
|
|
92
|
+
* uploaded reference into the next `sendMessage()`.
|
|
93
|
+
*/
|
|
94
|
+
attachFile(opts: AttachmentInput): Promise<void> {
|
|
95
|
+
return NativeNewinstanceChat.attachFile(opts);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Subscribe to a native event. Returns an unsubscribe function — call it
|
|
100
|
+
* when your component unmounts to avoid leaks.
|
|
101
|
+
*/
|
|
102
|
+
addListener<K extends EventName>(
|
|
103
|
+
event: K,
|
|
104
|
+
handler: EventHandler<K>
|
|
105
|
+
): () => void {
|
|
106
|
+
const sub: EmitterSubscription = emitter.addListener(
|
|
107
|
+
event,
|
|
108
|
+
handler as (e: unknown) => void
|
|
109
|
+
);
|
|
110
|
+
return () => sub.remove();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Tear down the native SDK. After this the instance is unusable —
|
|
115
|
+
* construct a new one if you need to chat again.
|
|
116
|
+
*/
|
|
117
|
+
destroy(): void {
|
|
118
|
+
NativeNewinstanceChat.destroy();
|
|
119
|
+
}
|
|
120
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public types for `react-native-newinstance-chat`.
|
|
3
|
+
*
|
|
4
|
+
* Shapes match what the native bridges produce, normalised across
|
|
5
|
+
* iOS / Android (e.g. message status / error type / connection state
|
|
6
|
+
* are lowercased string enums, not platform-specific enum values).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export interface NewinstanceChatConfig {
|
|
10
|
+
/** API key id from your newinstance.cloud dashboard. Never embed the secret half. */
|
|
11
|
+
apiKey: string;
|
|
12
|
+
/** Backend base URL. Defaults to `https://service.newinstance.cloud`. */
|
|
13
|
+
baseUrl?: string;
|
|
14
|
+
/** Subscription transport. `'sse'` (default in production), `'ws'`, or omit to let the server choose. */
|
|
15
|
+
transport?: 'sse' | 'ws';
|
|
16
|
+
/** Optional message pre-seeded as the first outbound message. */
|
|
17
|
+
initialMessage?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface ChatUser {
|
|
21
|
+
customerName: string;
|
|
22
|
+
customerEmail?: string;
|
|
23
|
+
customerId?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** A local file the native side reads bytes from. */
|
|
27
|
+
export interface AttachmentInput {
|
|
28
|
+
/** Local file URI: `file://...` (iOS) or `content://...` / `file://...` (Android). */
|
|
29
|
+
uri: string;
|
|
30
|
+
name: string;
|
|
31
|
+
mimeType: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export type ConnectionState =
|
|
35
|
+
| 'idle'
|
|
36
|
+
| 'connecting'
|
|
37
|
+
| 'connected'
|
|
38
|
+
| 'disconnected'
|
|
39
|
+
| 'offline';
|
|
40
|
+
|
|
41
|
+
export interface ChatMessage {
|
|
42
|
+
id: string;
|
|
43
|
+
/** Client-side id used to dedupe a sent message against its server echo. */
|
|
44
|
+
clientId?: string;
|
|
45
|
+
conversationId: string;
|
|
46
|
+
content: string;
|
|
47
|
+
/** Lowercased enum from the native side: `'text'`, `'image'`, etc. */
|
|
48
|
+
type: string;
|
|
49
|
+
/** Lowercased enum: `'sent'`, `'delivered'`, `'failed'`, etc. */
|
|
50
|
+
status: string;
|
|
51
|
+
/** Server-assigned monotonic sequence number for ordering. */
|
|
52
|
+
seq?: number;
|
|
53
|
+
/** ISO-8601 timestamp string. */
|
|
54
|
+
sentAt?: string;
|
|
55
|
+
/**
|
|
56
|
+
* Total persisted messages in the conversation as of this envelope.
|
|
57
|
+
* Only present on `messageReceived`. The SDK uses this for silent
|
|
58
|
+
* gap-fill — if the locally-rendered count is below this, it refetches.
|
|
59
|
+
*/
|
|
60
|
+
totalMessages?: number;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export type NewinstanceChatErrorType =
|
|
64
|
+
| 'network'
|
|
65
|
+
| 'validation'
|
|
66
|
+
| 'auth'
|
|
67
|
+
| 'system';
|
|
68
|
+
|
|
69
|
+
export interface NewinstanceChatError {
|
|
70
|
+
type: NewinstanceChatErrorType;
|
|
71
|
+
message: string;
|
|
72
|
+
recoverable: boolean;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Native event names. Subscribe with `sdk.addListener(event, handler)`. */
|
|
76
|
+
export interface EventMap {
|
|
77
|
+
messageReceived: (message: ChatMessage) => void;
|
|
78
|
+
messageSent: (message: ChatMessage) => void;
|
|
79
|
+
agentTypingChanged: (isTyping: boolean) => void;
|
|
80
|
+
connectionStateChanged: (state: ConnectionState) => void;
|
|
81
|
+
unreadCountChanged: (count: number) => void;
|
|
82
|
+
error: (e: NewinstanceChatError) => void;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export type EventName = keyof EventMap;
|
|
86
|
+
export type EventHandler<K extends EventName> = EventMap[K];
|