@incode-sdks/incode-integrate 0.3.0 → 0.4.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/README.md +9 -2
- package/agent.js +61 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -38,14 +38,15 @@ In an interactive terminal, the CLI asks for:
|
|
|
38
38
|
- generated Incode flow files under `src/`
|
|
39
39
|
- ignored local files such as `.env.local` and `.npmrc` when credentials are provided
|
|
40
40
|
|
|
41
|
-
Secrets are not written to
|
|
41
|
+
Secrets are not written to Gradle, Podfile, README, or committed generated TypeScript files.
|
|
42
42
|
|
|
43
43
|
When `--apply` receives tokens, it writes them only to ignored local files:
|
|
44
44
|
|
|
45
45
|
- `.env.local`: shell exports for `GITHUB_USERNAME`, `GITHUB_TOKEN`, `INCODE_API_URL`, optional `INCODE_API_KEY`, and optional `INCODE_SESSION_TOKEN`
|
|
46
46
|
- `.npmrc`: npm registry auth for the React Native SDK package
|
|
47
|
+
- `src/incodeRuntimeConfig.local.ts`: demo-app credential prefill generated from `.env.local`
|
|
47
48
|
|
|
48
|
-
|
|
49
|
+
React Native does not automatically load `.env.local` at runtime. The generated local runtime config lets the demo app prefill the API key or backend session token from ignored local values.
|
|
49
50
|
|
|
50
51
|
## Backend Sessions
|
|
51
52
|
|
|
@@ -59,6 +60,12 @@ In backend-session mode, the generated `src/IncodeExample.ts` appends `/0/` to t
|
|
|
59
60
|
|
|
60
61
|
The client app should pass the backend-created `session_token` as `sessionToken`; the helper maps it to the React Native SDK's `sessionConfig.token`.
|
|
61
62
|
|
|
63
|
+
## Online Dashboard Flows
|
|
64
|
+
|
|
65
|
+
When `--sdk-config online` is used, the generated helper puts the dashboard flow ID into `SESSION_CONFIG.configurationId` and starts onboarding with `IncodeSdk.startFlow({ sessionConfig })`.
|
|
66
|
+
|
|
67
|
+
Manual mode uses generated `flowConfig` modules with `IncodeSdk.startOnboarding(...)` or `startOnboardingSection(...)`.
|
|
68
|
+
|
|
62
69
|
## Scripted Examples
|
|
63
70
|
|
|
64
71
|
```sh
|
package/agent.js
CHANGED
|
@@ -164,6 +164,10 @@ function normalizeVersion(version) {
|
|
|
164
164
|
return trimmed || DEFAULT_SDK_VERSION;
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
+
function escapeRegExp(value) {
|
|
168
|
+
return String(value).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
169
|
+
}
|
|
170
|
+
|
|
167
171
|
function normalizeVariant(variant) {
|
|
168
172
|
const normalized = String(variant || "").trim().toLowerCase();
|
|
169
173
|
const aliases = {
|
|
@@ -457,6 +461,20 @@ function parseStringConstant(content, name) {
|
|
|
457
461
|
return double?.[1] || "";
|
|
458
462
|
}
|
|
459
463
|
|
|
464
|
+
function parseObjectStringProperty(content, name) {
|
|
465
|
+
const quoted = content.match(
|
|
466
|
+
new RegExp(`["']${escapeRegExp(name)}["']\\s*:\\s*["']([^"']*)["']`),
|
|
467
|
+
);
|
|
468
|
+
if (quoted) {
|
|
469
|
+
return quoted[1];
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
const unquoted = content.match(
|
|
473
|
+
new RegExp(`\\b${escapeRegExp(name)}\\b\\s*:\\s*["']([^"']*)["']`),
|
|
474
|
+
);
|
|
475
|
+
return unquoted?.[1] || "";
|
|
476
|
+
}
|
|
477
|
+
|
|
460
478
|
function parseBooleanConstant(content, name, fallback) {
|
|
461
479
|
const match = content.match(new RegExp(`export const ${name}(?::[^=]+)? = (true|false)`));
|
|
462
480
|
return match ? match[1] === "true" : fallback;
|
|
@@ -480,10 +498,14 @@ function extractConfigurationId(dashboardUrl) {
|
|
|
480
498
|
}
|
|
481
499
|
|
|
482
500
|
const fromPath = url.pathname.match(/(?:configuration|configurations|flow|flows)\/([^/?#]+)/i);
|
|
483
|
-
|
|
501
|
+
if (fromPath) {
|
|
502
|
+
return fromPath[1];
|
|
503
|
+
}
|
|
484
504
|
} catch {
|
|
485
|
-
|
|
505
|
+
// Fall through and allow a raw flow/configuration ID.
|
|
486
506
|
}
|
|
507
|
+
|
|
508
|
+
return /^[A-Za-z0-9_-]+$/.test(value) ? value : "";
|
|
487
509
|
}
|
|
488
510
|
|
|
489
511
|
function inferVariantFromDashboardUrl(dashboardUrl) {
|
|
@@ -613,6 +635,9 @@ function inferProductOptions(context) {
|
|
|
613
635
|
const sdkConfigMode = normalizeConfigMode(parseStringConstant(incodeFlow, "SDK_CONFIGURATION_MODE"), "manual");
|
|
614
636
|
const flowHandling = normalizeFlowHandling(parseStringConstant(incodeFlow, "FLOW_HANDLING"), "end-to-end");
|
|
615
637
|
const dashboardUrl = parseStringConstant(incodeFlow, "DASHBOARD_FLOW_URL");
|
|
638
|
+
const configurationId =
|
|
639
|
+
parseObjectStringProperty(incodeFlow, "configurationId") ||
|
|
640
|
+
extractConfigurationId(dashboardUrl);
|
|
616
641
|
const apiUrl = normalizeApiUrl(
|
|
617
642
|
localSecrets.INCODE_API_URL || parseStringConstant(incodeRuntimeConfig, "INCODE_DEFAULT_API_URL"),
|
|
618
643
|
API_URLS.demo.url,
|
|
@@ -634,7 +659,7 @@ function inferProductOptions(context) {
|
|
|
634
659
|
apiKeyProvided: Boolean(localSecrets.INCODE_API_KEY),
|
|
635
660
|
apiUrl,
|
|
636
661
|
backendSessions: localBackendSessions,
|
|
637
|
-
configurationId
|
|
662
|
+
configurationId,
|
|
638
663
|
dashboardUrl,
|
|
639
664
|
dynamicLocalization: androidAppBuildGradle.includes("com.incode.sdk:extensions"),
|
|
640
665
|
flowHandling,
|
|
@@ -651,6 +676,7 @@ function inferProductOptions(context) {
|
|
|
651
676
|
sdkConfigMode,
|
|
652
677
|
sdkVariant: currentDependency.variant,
|
|
653
678
|
sdkVersion: currentDependency.version,
|
|
679
|
+
sessionToken: localSecrets.INCODE_SESSION_TOKEN || "",
|
|
654
680
|
testMode,
|
|
655
681
|
videoStreaming: androidAppBuildGradle.includes("com.incode.sdk:video-streaming"),
|
|
656
682
|
};
|
|
@@ -766,6 +792,7 @@ async function promptForProductOptions(context, options) {
|
|
|
766
792
|
sdkConfigMode,
|
|
767
793
|
sdkVariant: variantForIdv(idv),
|
|
768
794
|
sdkVersion,
|
|
795
|
+
sessionToken: current.sessionToken,
|
|
769
796
|
videoStreaming: Boolean(IDV_PRESETS[idv].videoStreaming),
|
|
770
797
|
};
|
|
771
798
|
} finally {
|
|
@@ -836,6 +863,7 @@ function chooseProductOptions(context, options) {
|
|
|
836
863
|
sdkConfigMode,
|
|
837
864
|
sdkVariant: variantForIdv(idv),
|
|
838
865
|
sdkVersion: normalizeVersion(options.version || DEFAULT_SDK_VERSION),
|
|
866
|
+
sessionToken: current.sessionToken,
|
|
839
867
|
testMode: options.testMode === undefined ? current.testMode : options.testMode,
|
|
840
868
|
videoStreaming:
|
|
841
869
|
options.videoStreaming === undefined
|
|
@@ -882,8 +910,6 @@ export type FlowHandling = 'end-to-end' | 'step-by-step';
|
|
|
882
910
|
|
|
883
911
|
export const SDK_CONFIGURATION_MODE: SdkConfigurationMode = '${productOptions.sdkConfigMode}';
|
|
884
912
|
|
|
885
|
-
export const DASHBOARD_FLOW_URL = '${productOptions.dashboardUrl || ""}';
|
|
886
|
-
|
|
887
913
|
export const IDV_PRESET = '${productOptions.idv}' as const;
|
|
888
914
|
|
|
889
915
|
export const FLOW_HANDLING: FlowHandling = '${productOptions.flowHandling}';
|
|
@@ -925,6 +951,17 @@ export const INCODE_DEFAULT_TEST_MODE = ${productOptions.testMode};
|
|
|
925
951
|
`;
|
|
926
952
|
}
|
|
927
953
|
|
|
954
|
+
function createLocalRuntimeConfigFile(productOptions) {
|
|
955
|
+
const credential = productOptions.backendSessions
|
|
956
|
+
? productOptions.sessionToken
|
|
957
|
+
: productOptions.apiKey;
|
|
958
|
+
|
|
959
|
+
return `// Generated from ignored local env values for the demo app.
|
|
960
|
+
// Do not commit real credentials in this file.
|
|
961
|
+
export const INCODE_DEFAULT_CREDENTIAL = ${toTs(credential || "")};
|
|
962
|
+
`;
|
|
963
|
+
}
|
|
964
|
+
|
|
928
965
|
function createLocalCredentialEnvFile(productOptions) {
|
|
929
966
|
const lines = [
|
|
930
967
|
"# Local Incode SDK credentials and runtime values. This file is ignored by git.",
|
|
@@ -950,7 +987,11 @@ function createLocalCredentialEnvFile(productOptions) {
|
|
|
950
987
|
}
|
|
951
988
|
|
|
952
989
|
if (productOptions.backendSessions) {
|
|
953
|
-
|
|
990
|
+
if (productOptions.sessionToken) {
|
|
991
|
+
lines.push(`export INCODE_SESSION_TOKEN="${escapeEnvValue(productOptions.sessionToken)}"`);
|
|
992
|
+
} else {
|
|
993
|
+
lines.push('export INCODE_SESSION_TOKEN="${INCODE_SESSION_TOKEN:-<token-from-your-backend>}"');
|
|
994
|
+
}
|
|
954
995
|
}
|
|
955
996
|
|
|
956
997
|
return `${lines.join("\n")}\n`;
|
|
@@ -969,6 +1010,7 @@ import {
|
|
|
969
1010
|
FLOW_CONFIG,
|
|
970
1011
|
FLOW_HANDLING,
|
|
971
1012
|
FLOW_RECORD_SESSION_CONFIG,
|
|
1013
|
+
SDK_CONFIGURATION_MODE,
|
|
972
1014
|
SECTION_FLOW_CONFIGS,
|
|
973
1015
|
SESSION_CONFIG,
|
|
974
1016
|
} from './incodeFlow';
|
|
@@ -1020,6 +1062,10 @@ export async function startConfiguredOnboarding(options: StartIncodeOptions) {
|
|
|
1020
1062
|
|
|
1021
1063
|
const sessionConfig = buildSessionConfig(options);
|
|
1022
1064
|
|
|
1065
|
+
if (SDK_CONFIGURATION_MODE === 'online') {
|
|
1066
|
+
return IncodeSdk.startFlow({ sessionConfig });
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1023
1069
|
if (FLOW_HANDLING === 'step-by-step') {
|
|
1024
1070
|
const session = await IncodeSdk.setupOnboardingSession({ sessionConfig });
|
|
1025
1071
|
let lastResult: Awaited<ReturnType<typeof IncodeSdk.startOnboardingSection>> | undefined;
|
|
@@ -1091,7 +1137,7 @@ function generatePlan(context, sdkSelection, productOptions) {
|
|
|
1091
1137
|
const changes = [
|
|
1092
1138
|
{
|
|
1093
1139
|
action: "gitignore_entries",
|
|
1094
|
-
entries: [".env.local", ".incode.local.env", ".npmrc"],
|
|
1140
|
+
entries: [".env.local", ".incode.local.env", ".npmrc", "src/incodeRuntimeConfig.local.ts"],
|
|
1095
1141
|
file: ".gitignore",
|
|
1096
1142
|
title: "Keep local SDK credentials out of source control",
|
|
1097
1143
|
},
|
|
@@ -1145,6 +1191,12 @@ function generatePlan(context, sdkSelection, productOptions) {
|
|
|
1145
1191
|
file: "src/incodeRuntimeConfig.ts",
|
|
1146
1192
|
title: "Generate non-secret runtime defaults",
|
|
1147
1193
|
},
|
|
1194
|
+
{
|
|
1195
|
+
action: "write_file",
|
|
1196
|
+
content: createLocalRuntimeConfigFile(productOptions),
|
|
1197
|
+
file: "src/incodeRuntimeConfig.local.ts",
|
|
1198
|
+
title: "Generate ignored local runtime credential defaults",
|
|
1199
|
+
},
|
|
1148
1200
|
{
|
|
1149
1201
|
action: "write_file",
|
|
1150
1202
|
content: createExampleFile(),
|
|
@@ -1251,7 +1303,6 @@ function printPlan(context, plan, options) {
|
|
|
1251
1303
|
console.log(`Dashboard flow URL: ${product.dashboardUrl || "not provided"}`);
|
|
1252
1304
|
console.log(`Dashboard environment: ${labelForApiUrl(product.apiUrl)}`);
|
|
1253
1305
|
console.log(`Configuration ID: ${product.configurationId || "not inferred"}`);
|
|
1254
|
-
console.log("Dashboard flow config: will be fetched by API when the flow-config endpoint is connected.");
|
|
1255
1306
|
}
|
|
1256
1307
|
console.log(`IDV preset: ${product.idv}`);
|
|
1257
1308
|
console.log(`Flow handling: ${product.flowHandling}`);
|
|
@@ -1261,10 +1312,10 @@ function printPlan(context, plan, options) {
|
|
|
1261
1312
|
console.log(`Feature deps: ${featureDeps.join(", ") || "none"}`);
|
|
1262
1313
|
console.log("");
|
|
1263
1314
|
console.log(
|
|
1264
|
-
"Secrets are never written to
|
|
1315
|
+
"Secrets are never written to Gradle, Podfile, README, or committed generated TypeScript files.",
|
|
1265
1316
|
);
|
|
1266
1317
|
console.log(
|
|
1267
|
-
"When --apply receives tokens, they are written only to ignored local files: .env.local and .
|
|
1318
|
+
"When --apply receives tokens, they are written only to ignored local files: .env.local, .npmrc, and src/incodeRuntimeConfig.local.ts.",
|
|
1268
1319
|
);
|
|
1269
1320
|
console.log("");
|
|
1270
1321
|
console.log(options.apply ? "Applying changes:" : "Planned changes:");
|