@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.
Files changed (3) hide show
  1. package/README.md +9 -2
  2. package/agent.js +61 -10
  3. 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 generated TypeScript, Gradle, Podfile, or README files.
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
- The React Native app does not automatically load `.env.local`; that file is for local shell and build tooling.
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
- return fromPath?.[1] || "";
501
+ if (fromPath) {
502
+ return fromPath[1];
503
+ }
484
504
  } catch {
485
- return "";
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: extractConfigurationId(dashboardUrl),
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
- lines.push('export INCODE_SESSION_TOKEN="${INCODE_SESSION_TOKEN:-<token-from-your-backend>}"');
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 generated TypeScript, Gradle, Podfile, or README files.",
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 .npmrc.",
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:");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@incode-sdks/incode-integrate",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "CLI integration auditor and fixer for adding the Incode React Native SDK to client apps.",
5
5
  "main": "agent.js",
6
6
  "bin": {