@nihinmedia/medgen-react-native 1.0.9
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 +62 -0
- package/README.md +162 -0
- package/SECURITY.md +101 -0
- package/lib/commonjs/MedGenWebView.js +172 -0
- package/lib/commonjs/bridge.js +135 -0
- package/lib/commonjs/client.js +350 -0
- package/lib/commonjs/index.js +199 -0
- package/lib/commonjs/types.js +27 -0
- package/lib/module/MedGenWebView.js +137 -0
- package/lib/module/bridge.js +127 -0
- package/lib/module/client.js +298 -0
- package/lib/module/index.js +147 -0
- package/lib/module/types.js +17 -0
- package/lib/typescript/MedGenWebView.d.ts +18 -0
- package/lib/typescript/bridge.d.ts +12 -0
- package/lib/typescript/client.d.ts +28 -0
- package/lib/typescript/index.d.ts +21 -0
- package/lib/typescript/types.d.ts +108 -0
- package/package.json +97 -0
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
|
|
7
|
+
exports.apiBase = exports.SDK_VERSION = void 0;
|
|
8
|
+
|
|
9
|
+
exports.buildEmbedUrl = buildEmbedUrl;
|
|
10
|
+
|
|
11
|
+
exports.clearCredentials = clearCredentials;
|
|
12
|
+
|
|
13
|
+
exports.configure = configure;
|
|
14
|
+
|
|
15
|
+
exports.embedBase = void 0;
|
|
16
|
+
|
|
17
|
+
exports.emit = emit;
|
|
18
|
+
|
|
19
|
+
exports.exchange = exchange;
|
|
20
|
+
|
|
21
|
+
exports.parseCapabilities = parseCapabilities;
|
|
22
|
+
|
|
23
|
+
exports.readCredentials = readCredentials;
|
|
24
|
+
|
|
25
|
+
exports.requireConfig = requireConfig;
|
|
26
|
+
|
|
27
|
+
exports.resetConfig = resetConfig;
|
|
28
|
+
|
|
29
|
+
exports.storeCredentials = storeCredentials;
|
|
30
|
+
|
|
31
|
+
var _reactNative = require("react-native");
|
|
32
|
+
|
|
33
|
+
var Keychain = _interopRequireWildcard(require("react-native-keychain"));
|
|
34
|
+
|
|
35
|
+
var _types = require("./types");
|
|
36
|
+
|
|
37
|
+
function _interopRequireWildcard(e, t) {
|
|
38
|
+
if ("function" == typeof WeakMap) var r = new WeakMap, n = new WeakMap;
|
|
39
|
+
return (_interopRequireWildcard = function(e, t) {
|
|
40
|
+
if (!t && e && e.__esModule) return e;
|
|
41
|
+
var o, i, f = {
|
|
42
|
+
__proto__: null,
|
|
43
|
+
default: e
|
|
44
|
+
};
|
|
45
|
+
if (null === e || "object" != typeof e && "function" != typeof e) return f;
|
|
46
|
+
if (o = t ? n : r) {
|
|
47
|
+
if (o.has(e)) return o.get(e);
|
|
48
|
+
o.set(e, f);
|
|
49
|
+
}
|
|
50
|
+
for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]);
|
|
51
|
+
return f;
|
|
52
|
+
})(e, t);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const KEYCHAIN_SERVICE = "jp.nihinmedia.medgen";
|
|
56
|
+
|
|
57
|
+
const ASSERTION_TIMEOUT_MS = 1e4;
|
|
58
|
+
|
|
59
|
+
const ATTESTATION_TIMEOUT_MS = 15e3;
|
|
60
|
+
|
|
61
|
+
const SDK_VERSION = exports.SDK_VERSION = "1.0.9";
|
|
62
|
+
|
|
63
|
+
const DEFAULT_API = {
|
|
64
|
+
development: "https://dev.sugoimed.com",
|
|
65
|
+
staging: "https://staging.sugoimed.com",
|
|
66
|
+
production: "https://medgen.nihinmedia.jp"
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const DEFAULT_EMBED = {
|
|
70
|
+
development: "https://dev.sugoimed.com",
|
|
71
|
+
staging: "https://staging.sugoimed.com",
|
|
72
|
+
production: "https://medgen.nihinmedia.jp"
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
let config = null;
|
|
76
|
+
|
|
77
|
+
function configure(cfg) {
|
|
78
|
+
config = cfg;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function resetConfig() {
|
|
82
|
+
config = null;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function requireConfig() {
|
|
86
|
+
if (!config) {
|
|
87
|
+
throw new _types.MedGenError("NOT_INITIALIZED", "Call MedGen.initialize() before present()");
|
|
88
|
+
}
|
|
89
|
+
return config;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function requireHttps(url, field) {
|
|
93
|
+
const lower = url.toLowerCase();
|
|
94
|
+
const isLocal = lower.startsWith("http://localhost") || lower.startsWith("http://127.0.0.1");
|
|
95
|
+
if (!lower.startsWith("https://") && !isLocal) {
|
|
96
|
+
throw new _types.MedGenError("NOT_INITIALIZED", `${field} must use https:// — refusing to send an assertion over plaintext`);
|
|
97
|
+
}
|
|
98
|
+
return url.replace(/\/+$/, "");
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const apiBase = () => {
|
|
102
|
+
const cfg = requireConfig();
|
|
103
|
+
const base = cfg.apiBaseUrl ?? DEFAULT_API[cfg.environment] ?? DEFAULT_API.staging;
|
|
104
|
+
return requireHttps(base, "apiBaseUrl");
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
exports.apiBase = apiBase;
|
|
108
|
+
|
|
109
|
+
const embedBase = () => {
|
|
110
|
+
const cfg = requireConfig();
|
|
111
|
+
const base = cfg.embedBaseUrl ?? DEFAULT_EMBED[cfg.environment] ?? DEFAULT_EMBED.staging;
|
|
112
|
+
return requireHttps(base, "embedBaseUrl");
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
exports.embedBase = embedBase;
|
|
116
|
+
|
|
117
|
+
function emit(name, detail) {
|
|
118
|
+
const handler = config?.onEvent;
|
|
119
|
+
if (!handler) return;
|
|
120
|
+
const event = {
|
|
121
|
+
name: name,
|
|
122
|
+
at: Date.now(),
|
|
123
|
+
detail: detail
|
|
124
|
+
};
|
|
125
|
+
try {
|
|
126
|
+
handler(event);
|
|
127
|
+
} catch {}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async function storeCredentials(creds) {
|
|
131
|
+
await Keychain.setGenericPassword("medgen", JSON.stringify(creds), {
|
|
132
|
+
service: KEYCHAIN_SERVICE,
|
|
133
|
+
accessible: Keychain.ACCESSIBLE.AFTER_FIRST_UNLOCK_THIS_DEVICE_ONLY
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
async function readCredentials() {
|
|
138
|
+
try {
|
|
139
|
+
const res = await Keychain.getGenericPassword({
|
|
140
|
+
service: KEYCHAIN_SERVICE
|
|
141
|
+
});
|
|
142
|
+
if (!res) return null;
|
|
143
|
+
return JSON.parse(res.password);
|
|
144
|
+
} catch {
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
async function clearCredentials() {
|
|
150
|
+
await Keychain.resetGenericPassword({
|
|
151
|
+
service: KEYCHAIN_SERVICE
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function withTimeout(p, ms, code, what) {
|
|
156
|
+
let timer;
|
|
157
|
+
const timeout = new Promise((_, reject) => {
|
|
158
|
+
timer = setTimeout(() => reject(new _types.MedGenError(code, `${what} exceeded ${ms}ms`, true)), ms);
|
|
159
|
+
});
|
|
160
|
+
return Promise.race([ p, timeout ]).finally(() => clearTimeout(timer));
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
async function fetchAssertion() {
|
|
164
|
+
const {assertionProvider: assertionProvider, assertion: assertion} = requireConfig();
|
|
165
|
+
if (!assertionProvider) {
|
|
166
|
+
if (assertion) return assertion;
|
|
167
|
+
throw new _types.MedGenError("NOT_INITIALIZED", "Set assertionProvider (or, to try the SDK once, assertion) in MedGen.initialize()");
|
|
168
|
+
}
|
|
169
|
+
try {
|
|
170
|
+
return await withTimeout(assertionProvider(), ASSERTION_TIMEOUT_MS, "ASSERTION_PROVIDER_TIMEOUT", "Assertion provider");
|
|
171
|
+
} catch (e) {
|
|
172
|
+
if (e instanceof _types.MedGenError) throw e;
|
|
173
|
+
throw new _types.MedGenError("ASSERTION_PROVIDER_FAILED", e instanceof Error ? e.message : "Assertion provider failed", true);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
async function fetchAttestation(assertion) {
|
|
178
|
+
const {attestationProvider: attestationProvider} = requireConfig();
|
|
179
|
+
if (!attestationProvider) return "";
|
|
180
|
+
try {
|
|
181
|
+
return await withTimeout(attestationProvider(assertion), ATTESTATION_TIMEOUT_MS, "ATTESTATION_FAILED", "Attestation provider");
|
|
182
|
+
} catch (e) {
|
|
183
|
+
if (e instanceof _types.MedGenError) throw e;
|
|
184
|
+
throw new _types.MedGenError("ATTESTATION_FAILED", e instanceof Error ? e.message : "Attestation provider failed", true);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const CAPABILITY_DEFAULTS = {
|
|
189
|
+
theming: false,
|
|
190
|
+
customLogo: false,
|
|
191
|
+
hideAttribution: false,
|
|
192
|
+
quickAnswer: true,
|
|
193
|
+
detailedAnswer: true,
|
|
194
|
+
japaneseAnswer: true,
|
|
195
|
+
dictation: false,
|
|
196
|
+
fileUpload: false,
|
|
197
|
+
clipboard: true,
|
|
198
|
+
richClipboard: true,
|
|
199
|
+
share: true,
|
|
200
|
+
chatHistory: true,
|
|
201
|
+
bookmarks: false,
|
|
202
|
+
citationsPanel: true,
|
|
203
|
+
directLink: true
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
function parseCapabilities(raw) {
|
|
207
|
+
const src = raw ?? {};
|
|
208
|
+
const pick = (key, fallback) => typeof src[key] === "boolean" ? src[key] : fallback;
|
|
209
|
+
return {
|
|
210
|
+
theming: pick("theming", CAPABILITY_DEFAULTS.theming),
|
|
211
|
+
customLogo: pick("custom_logo", CAPABILITY_DEFAULTS.customLogo),
|
|
212
|
+
hideAttribution: pick("hide_attribution", CAPABILITY_DEFAULTS.hideAttribution),
|
|
213
|
+
quickAnswer: pick("quick_answer", CAPABILITY_DEFAULTS.quickAnswer),
|
|
214
|
+
detailedAnswer: pick("detailed_answer", CAPABILITY_DEFAULTS.detailedAnswer),
|
|
215
|
+
japaneseAnswer: pick("japanese_answer", CAPABILITY_DEFAULTS.japaneseAnswer),
|
|
216
|
+
dictation: pick("dictation", CAPABILITY_DEFAULTS.dictation),
|
|
217
|
+
fileUpload: pick("file_upload", CAPABILITY_DEFAULTS.fileUpload),
|
|
218
|
+
clipboard: pick("clipboard", CAPABILITY_DEFAULTS.clipboard),
|
|
219
|
+
richClipboard: pick("rich_clipboard", CAPABILITY_DEFAULTS.richClipboard),
|
|
220
|
+
share: pick("share", CAPABILITY_DEFAULTS.share),
|
|
221
|
+
chatHistory: pick("chat_history", CAPABILITY_DEFAULTS.chatHistory),
|
|
222
|
+
bookmarks: pick("bookmarks", CAPABILITY_DEFAULTS.bookmarks),
|
|
223
|
+
citationsPanel: pick("citations_panel", CAPABILITY_DEFAULTS.citationsPanel),
|
|
224
|
+
directLink: pick("direct_link", CAPABILITY_DEFAULTS.directLink)
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const CLIENT_BY_PLATFORM = {
|
|
229
|
+
ios: "sdk-ios",
|
|
230
|
+
android: "sdk-android"
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
async function exchange() {
|
|
234
|
+
emit("exchange.started");
|
|
235
|
+
const assertion = await fetchAssertion();
|
|
236
|
+
const attestation = await fetchAttestation(assertion);
|
|
237
|
+
const client = CLIENT_BY_PLATFORM[_reactNative.Platform.OS] ?? "sdk-ios";
|
|
238
|
+
const headers = {
|
|
239
|
+
"Content-Type": "application/json",
|
|
240
|
+
"X-MedGen-Client": `rn/${SDK_VERSION}`
|
|
241
|
+
};
|
|
242
|
+
if (attestation) headers["X-MedGen-Attestation"] = attestation;
|
|
243
|
+
let res;
|
|
244
|
+
try {
|
|
245
|
+
res = await fetch(`${apiBase()}/api/v1/partner/session/exchange`, {
|
|
246
|
+
method: "POST",
|
|
247
|
+
headers: headers,
|
|
248
|
+
body: JSON.stringify({
|
|
249
|
+
assertion: assertion,
|
|
250
|
+
client: client
|
|
251
|
+
})
|
|
252
|
+
});
|
|
253
|
+
} catch (e) {
|
|
254
|
+
const err = new _types.MedGenError("NETWORK_UNAVAILABLE", e instanceof Error ? e.message : "Network unavailable", true);
|
|
255
|
+
emit("exchange.failed", {
|
|
256
|
+
code: err.code
|
|
257
|
+
});
|
|
258
|
+
throw err;
|
|
259
|
+
}
|
|
260
|
+
const body = await res.json().catch(() => ({}));
|
|
261
|
+
if (!res.ok) {
|
|
262
|
+
const err = new _types.MedGenError(body.error ?? "UNKNOWN", body.message ?? "Exchange failed", Boolean(body.retryable), body.support_reference);
|
|
263
|
+
emit("exchange.failed", {
|
|
264
|
+
code: err.code,
|
|
265
|
+
status: res.status
|
|
266
|
+
});
|
|
267
|
+
throw err;
|
|
268
|
+
}
|
|
269
|
+
const access = body.access;
|
|
270
|
+
const refresh = body.refresh;
|
|
271
|
+
if (typeof access !== "string" || !access || typeof refresh !== "string" || !refresh) {
|
|
272
|
+
const err = new _types.MedGenError("UNKNOWN", "Exchange response is missing session tokens", true);
|
|
273
|
+
emit("exchange.failed", {
|
|
274
|
+
code: err.code
|
|
275
|
+
});
|
|
276
|
+
throw err;
|
|
277
|
+
}
|
|
278
|
+
if (typeof body.handoff_code !== "string" || !body.handoff_code) {
|
|
279
|
+
const err = new _types.MedGenError("UNKNOWN", "Exchange response is missing a handoff code", true);
|
|
280
|
+
emit("exchange.failed", {
|
|
281
|
+
code: err.code
|
|
282
|
+
});
|
|
283
|
+
throw err;
|
|
284
|
+
}
|
|
285
|
+
await storeCredentials({
|
|
286
|
+
access: access,
|
|
287
|
+
refresh: refresh
|
|
288
|
+
});
|
|
289
|
+
const user = body.user ?? {};
|
|
290
|
+
const partner = body.partner ?? {};
|
|
291
|
+
const result = {
|
|
292
|
+
handoffCode: body.handoff_code,
|
|
293
|
+
isNewUser: Boolean(user.is_new),
|
|
294
|
+
emailCollisionPending: body.error === "EMAIL_COLLISION_PENDING",
|
|
295
|
+
brandingVersion: String(partner.branding_version ?? "1"),
|
|
296
|
+
capabilities: parseCapabilities(partner.capabilities ?? body.capabilities)
|
|
297
|
+
};
|
|
298
|
+
emit("exchange.succeeded", {
|
|
299
|
+
isNewUser: result.isNewUser,
|
|
300
|
+
emailCollisionPending: result.emailCollisionPending
|
|
301
|
+
});
|
|
302
|
+
return result;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const B64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
306
|
+
|
|
307
|
+
function toBase64(input) {
|
|
308
|
+
const bytes = [];
|
|
309
|
+
const utf8 = encodeURIComponent(input);
|
|
310
|
+
for (let i = 0; i < utf8.length; i += 1) {
|
|
311
|
+
if (utf8[i] === "%") {
|
|
312
|
+
bytes.push(parseInt(utf8.substr(i + 1, 2), 16));
|
|
313
|
+
i += 2;
|
|
314
|
+
} else {
|
|
315
|
+
bytes.push(utf8.charCodeAt(i));
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
let out = "";
|
|
319
|
+
for (let i = 0; i < bytes.length; i += 3) {
|
|
320
|
+
const b0 = bytes[i];
|
|
321
|
+
const b1 = bytes[i + 1];
|
|
322
|
+
const b2 = bytes[i + 2];
|
|
323
|
+
out += B64_ALPHABET[b0 >> 2];
|
|
324
|
+
out += B64_ALPHABET[(b0 & 3) << 4 | (b1 ?? 0) >> 4];
|
|
325
|
+
out += b1 === undefined ? "=" : B64_ALPHABET[(b1 & 15) << 2 | (b2 ?? 0) >> 6];
|
|
326
|
+
out += b2 === undefined ? "=" : B64_ALPHABET[b2 & 63];
|
|
327
|
+
}
|
|
328
|
+
return out;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function buildEmbedUrl(handoffCode, entryQuestion, capabilities) {
|
|
332
|
+
const cfg = requireConfig();
|
|
333
|
+
const params = [ [ "hc", handoffCode ], [ "locale", cfg.locale ?? "ja" ] ];
|
|
334
|
+
if (cfg.theme && capabilities?.theming !== false) {
|
|
335
|
+
const branding = {
|
|
336
|
+
colors: {
|
|
337
|
+
primary: cfg.theme.primary,
|
|
338
|
+
secondary: cfg.theme.secondary,
|
|
339
|
+
accent: cfg.theme.accent,
|
|
340
|
+
surface: cfg.theme.surface,
|
|
341
|
+
onSurface: cfg.theme.onSurface
|
|
342
|
+
},
|
|
343
|
+
colorsDark: cfg.theme.darkVariant
|
|
344
|
+
};
|
|
345
|
+
params.push([ "theme", toBase64(JSON.stringify(branding)) ]);
|
|
346
|
+
}
|
|
347
|
+
if (entryQuestion) params.push([ "q", entryQuestion ]);
|
|
348
|
+
const query = params.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`).join("&");
|
|
349
|
+
return `${embedBase()}/embed?${query}`;
|
|
350
|
+
}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
|
|
7
|
+
var _exportNames = {
|
|
8
|
+
MedGen: true,
|
|
9
|
+
MedGenHost: true,
|
|
10
|
+
MedGenSurface: true,
|
|
11
|
+
SDK_VERSION: true
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
exports.MedGenSurface = exports.MedGenHost = exports.MedGen = void 0;
|
|
15
|
+
|
|
16
|
+
Object.defineProperty(exports, "SDK_VERSION", {
|
|
17
|
+
enumerable: true,
|
|
18
|
+
get: function() {
|
|
19
|
+
return _client.SDK_VERSION;
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
24
|
+
|
|
25
|
+
var _reactNative = require("react-native");
|
|
26
|
+
|
|
27
|
+
var _client = require("./client");
|
|
28
|
+
|
|
29
|
+
var _MedGenWebView = require("./MedGenWebView");
|
|
30
|
+
|
|
31
|
+
var _types = require("./types");
|
|
32
|
+
|
|
33
|
+
Object.keys(_types).forEach(function(key) {
|
|
34
|
+
if (key === "default" || key === "__esModule") return;
|
|
35
|
+
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
|
|
36
|
+
if (key in exports && exports[key] === _types[key]) return;
|
|
37
|
+
Object.defineProperty(exports, key, {
|
|
38
|
+
enumerable: true,
|
|
39
|
+
get: function() {
|
|
40
|
+
return _types[key];
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
function _interopRequireWildcard(e, t) {
|
|
46
|
+
if ("function" == typeof WeakMap) var r = new WeakMap, n = new WeakMap;
|
|
47
|
+
return (_interopRequireWildcard = function(e, t) {
|
|
48
|
+
if (!t && e && e.__esModule) return e;
|
|
49
|
+
var o, i, f = {
|
|
50
|
+
__proto__: null,
|
|
51
|
+
default: e
|
|
52
|
+
};
|
|
53
|
+
if (null === e || "object" != typeof e && "function" != typeof e) return f;
|
|
54
|
+
if (o = t ? n : r) {
|
|
55
|
+
if (o.has(e)) return o.get(e);
|
|
56
|
+
o.set(e, f);
|
|
57
|
+
}
|
|
58
|
+
for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]);
|
|
59
|
+
return f;
|
|
60
|
+
})(e, t);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const hostRef = {
|
|
64
|
+
current: null
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const teardowns = new Set;
|
|
68
|
+
|
|
69
|
+
const MedGen = exports.MedGen = {
|
|
70
|
+
initialize(config) {
|
|
71
|
+
if (!config.assertionProvider && !config.assertion) {
|
|
72
|
+
throw new _types.MedGenError("NOT_INITIALIZED", "MedGen.initialize() needs assertionProvider (or, to try the SDK once, assertion)");
|
|
73
|
+
}
|
|
74
|
+
if (!config.assertionProvider && config.assertion) {
|
|
75
|
+
if (typeof __DEV__ !== "undefined" && !__DEV__) {
|
|
76
|
+
throw new _types.MedGenError("NOT_INITIALIZED", "A static `assertion` cannot be used in a release build — it is " + "single-use and cannot be refreshed. Set `assertionProvider`.");
|
|
77
|
+
}
|
|
78
|
+
console.warn("[MedGen] Using a static `assertion`. It is single-use and expires " + "after 120s, so only the first present() will succeed. Set " + "`assertionProvider` before shipping.");
|
|
79
|
+
}
|
|
80
|
+
(0, _client.configure)(config);
|
|
81
|
+
},
|
|
82
|
+
async present(options) {
|
|
83
|
+
if (!hostRef.current) {
|
|
84
|
+
throw new _types.MedGenError("NOT_INITIALIZED", "Mount <MedGenHost /> near the root of your app");
|
|
85
|
+
}
|
|
86
|
+
await hostRef.current(options);
|
|
87
|
+
},
|
|
88
|
+
async signOut() {
|
|
89
|
+
teardowns.forEach(fn => {
|
|
90
|
+
try {
|
|
91
|
+
fn();
|
|
92
|
+
} catch {}
|
|
93
|
+
});
|
|
94
|
+
await (0, _client.clearCredentials)();
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const MedGenHost = () => {
|
|
99
|
+
const [url, setUrl] = (0, _react.useState)(null);
|
|
100
|
+
const [capabilities, setCapabilities] = (0, _react.useState)(null);
|
|
101
|
+
const present = (0, _react.useCallback)(async options => {
|
|
102
|
+
const result = await (0, _client.exchange)();
|
|
103
|
+
setCapabilities(result.capabilities);
|
|
104
|
+
setUrl((0, _client.buildEmbedUrl)(result.handoffCode, options?.entryQuestion, result.capabilities));
|
|
105
|
+
(0, _client.emit)("surface.opened");
|
|
106
|
+
}, []);
|
|
107
|
+
(0, _react.useEffect)(() => {
|
|
108
|
+
hostRef.current = present;
|
|
109
|
+
return () => {
|
|
110
|
+
if (hostRef.current === present) hostRef.current = null;
|
|
111
|
+
};
|
|
112
|
+
}, [ present ]);
|
|
113
|
+
const close = (0, _react.useCallback)(() => {
|
|
114
|
+
setUrl(null);
|
|
115
|
+
setCapabilities(null);
|
|
116
|
+
(0, _client.emit)("surface.closed");
|
|
117
|
+
}, []);
|
|
118
|
+
(0, _react.useEffect)(() => {
|
|
119
|
+
teardowns.add(close);
|
|
120
|
+
return () => {
|
|
121
|
+
teardowns.delete(close);
|
|
122
|
+
};
|
|
123
|
+
}, [ close ]);
|
|
124
|
+
return _react.default.createElement(_reactNative.Modal, {
|
|
125
|
+
visible: url !== null,
|
|
126
|
+
animationType: "slide",
|
|
127
|
+
presentationStyle: "fullScreen",
|
|
128
|
+
onRequestClose: close
|
|
129
|
+
}, _react.default.createElement(_reactNative.SafeAreaView, {
|
|
130
|
+
style: styles.container
|
|
131
|
+
}, url && capabilities ? _react.default.createElement(_MedGenWebView.MedGenWebView, {
|
|
132
|
+
url: url,
|
|
133
|
+
handlers: (0, _client.requireConfig)().nativeHandlers ?? {},
|
|
134
|
+
capabilities: capabilities,
|
|
135
|
+
onClose: close
|
|
136
|
+
}) : null));
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
exports.MedGenHost = MedGenHost;
|
|
140
|
+
|
|
141
|
+
const MedGenSurface = ({visible: visible = true, options: options, onError: onError}) => {
|
|
142
|
+
const [url, setUrl] = (0, _react.useState)(null);
|
|
143
|
+
const [capabilities, setCapabilities] = (0, _react.useState)(null);
|
|
144
|
+
const [loading, setLoading] = (0, _react.useState)(false);
|
|
145
|
+
const started = (0, _react.useRef)(false);
|
|
146
|
+
(0, _react.useEffect)(() => {
|
|
147
|
+
if (!visible || started.current) return;
|
|
148
|
+
started.current = true;
|
|
149
|
+
setLoading(true);
|
|
150
|
+
(0, _client.exchange)().then(result => {
|
|
151
|
+
setCapabilities(result.capabilities);
|
|
152
|
+
setUrl((0, _client.buildEmbedUrl)(result.handoffCode, options?.entryQuestion, result.capabilities));
|
|
153
|
+
(0, _client.emit)("surface.opened");
|
|
154
|
+
}).catch(e => {
|
|
155
|
+
started.current = false;
|
|
156
|
+
onError?.(e);
|
|
157
|
+
}).finally(() => setLoading(false));
|
|
158
|
+
}, [ visible, options, onError ]);
|
|
159
|
+
(0, _react.useEffect)(() => {
|
|
160
|
+
const reset = () => {
|
|
161
|
+
setUrl(null);
|
|
162
|
+
setCapabilities(null);
|
|
163
|
+
started.current = false;
|
|
164
|
+
};
|
|
165
|
+
teardowns.add(reset);
|
|
166
|
+
return () => {
|
|
167
|
+
teardowns.delete(reset);
|
|
168
|
+
};
|
|
169
|
+
}, []);
|
|
170
|
+
return _react.default.createElement(_reactNative.View, {
|
|
171
|
+
style: [ styles.container, !visible && styles.hidden ],
|
|
172
|
+
pointerEvents: visible ? "auto" : "none"
|
|
173
|
+
}, url && capabilities ? _react.default.createElement(_MedGenWebView.MedGenWebView, {
|
|
174
|
+
url: url,
|
|
175
|
+
handlers: (0, _client.requireConfig)().nativeHandlers ?? {},
|
|
176
|
+
capabilities: capabilities,
|
|
177
|
+
onClose: () => undefined
|
|
178
|
+
}) : _react.default.createElement(_reactNative.View, {
|
|
179
|
+
style: styles.loading
|
|
180
|
+
}, loading ? _react.default.createElement(_reactNative.ActivityIndicator, {
|
|
181
|
+
size: "large"
|
|
182
|
+
}) : null));
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
exports.MedGenSurface = MedGenSurface;
|
|
186
|
+
|
|
187
|
+
const styles = _reactNative.StyleSheet.create({
|
|
188
|
+
container: {
|
|
189
|
+
flex: 1
|
|
190
|
+
},
|
|
191
|
+
hidden: {
|
|
192
|
+
display: "none"
|
|
193
|
+
},
|
|
194
|
+
loading: {
|
|
195
|
+
flex: 1,
|
|
196
|
+
alignItems: "center",
|
|
197
|
+
justifyContent: "center"
|
|
198
|
+
}
|
|
199
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
|
|
7
|
+
exports.MedGenError = exports.MedGenEnvironment = void 0;
|
|
8
|
+
|
|
9
|
+
let MedGenEnvironment = exports.MedGenEnvironment = function(MedGenEnvironment) {
|
|
10
|
+
MedGenEnvironment["Development"] = "development";
|
|
11
|
+
MedGenEnvironment["Staging"] = "staging";
|
|
12
|
+
MedGenEnvironment["Production"] = "production";
|
|
13
|
+
return MedGenEnvironment;
|
|
14
|
+
}({});
|
|
15
|
+
|
|
16
|
+
class MedGenError extends Error {
|
|
17
|
+
constructor(code, message, retryable = false, supportReference) {
|
|
18
|
+
super(message);
|
|
19
|
+
this.name = "MedGenError";
|
|
20
|
+
this.code = code;
|
|
21
|
+
this.retryable = retryable;
|
|
22
|
+
this.supportReference = supportReference;
|
|
23
|
+
Object.setPrototypeOf(this, MedGenError.prototype);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
exports.MedGenError = MedGenError;
|