@crumbsdk/react-native 0.0.1-rc.4 → 0.0.1-rc.5

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 CHANGED
@@ -4,6 +4,16 @@ The official Nitro Module adapter for Crumb. It is intentionally thin: the
4
4
  published Swift and Kotlin SDKs continue to own reporter presentation,
5
5
  screenshot masking, diagnostics, durable storage, and upload.
6
6
 
7
+ ## Guided setup preview
8
+
9
+ The rc.5 candidate includes guided setup and automatic source-map uploads through
10
+ the React Native package. See the [React Native and Expo setup guide](../../docs/react-native-setup.md).
11
+ These commands are not available in the published rc.4 package yet. The existing
12
+ installation below remains available while the new candidate is validated.
13
+ See the [rc.5 release notes](../../docs/releases/0.0.1-rc.5.md) for exact candidate
14
+ installation and upgrade instructions. The uploader is included automatically;
15
+ its separate package version is an implementation dependency, not another setup step.
16
+
7
17
  ## Requirements
8
18
 
9
19
  - React Native 0.79 or newer
@@ -73,6 +73,7 @@ android {
73
73
  }
74
74
  jniLibs {
75
75
  excludes += [
76
+ "**/libNitroModules.so",
76
77
  "**/libc++_shared.so",
77
78
  "**/libfbjni.so",
78
79
  "**/libjsi.so",
package/app.plugin.js CHANGED
@@ -1,21 +1,51 @@
1
1
  const { configurePodfile } = require('./plugin/podfile.cjs');
2
2
  const { name, version } = require('./package.json');
3
+ const {
4
+ configureXcodeProject,
5
+ configureGradle,
6
+ } = require('./plugin/build-hooks.cjs');
7
+ const { readConfig } = require('./tools/config.cjs');
3
8
 
4
9
  module.exports = function withCrumb(config) {
5
10
  // Resolve Expo from the consuming app, including non-hoisted workspaces.
6
- const { withPodfile, createRunOncePlugin } = require(
11
+ const {
12
+ withPodfile,
13
+ withXcodeProject,
14
+ withAppBuildGradle,
15
+ createRunOncePlugin,
16
+ } = require(
7
17
  require.resolve('expo/config-plugins', {
8
18
  paths: [config._internal?.projectRoot ?? process.cwd()],
9
19
  })
10
20
  );
11
21
  return createRunOncePlugin(
12
- (appConfig) =>
13
- withPodfile(appConfig, (modConfig) => {
22
+ (appConfig) => {
23
+ appConfig = withPodfile(appConfig, (modConfig) => {
14
24
  modConfig.modResults.contents = configurePodfile(
15
25
  modConfig.modResults.contents
16
26
  );
17
27
  return modConfig;
18
- }),
28
+ });
29
+ if (
30
+ !readConfig(config._internal?.projectRoot ?? process.cwd()).sourceMaps
31
+ .enabled
32
+ )
33
+ return appConfig;
34
+ appConfig = withXcodeProject(appConfig, (modConfig) => {
35
+ configureXcodeProject(modConfig.modResults);
36
+ return modConfig;
37
+ });
38
+ return withAppBuildGradle(appConfig, (modConfig) => {
39
+ if (modConfig.modResults.language !== 'groovy')
40
+ throw new Error(
41
+ 'Crumb automatic setup needs a Groovy app build file. Use the manual build-hook instructions for Kotlin DSL.'
42
+ );
43
+ modConfig.modResults.contents = configureGradle(
44
+ modConfig.modResults.contents
45
+ );
46
+ return modConfig;
47
+ });
48
+ },
19
49
  name,
20
50
  version
21
51
  )(config);
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+
3
+ export function withBuildRelease(configuration) {
4
+ const bundleVersion = globalThis.__CRUMB_BUNDLE_VERSION__;
5
+ if (typeof bundleVersion !== 'string' || !/^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$/.test(bundleVersion)) {
6
+ return configuration;
7
+ }
8
+ if (configuration.release?.bundleVersion !== undefined && configuration.release.bundleVersion !== bundleVersion) {
9
+ throw new TypeError('Crumb release.bundleVersion conflicts with the generated build identity. Remove the manual value or disable automatic source-map setup.');
10
+ }
11
+ return {
12
+ ...configuration,
13
+ release: {
14
+ ...configuration.release,
15
+ bundleVersion
16
+ }
17
+ };
18
+ }
19
+ //# sourceMappingURL=build-release.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["withBuildRelease","configuration","bundleVersion","globalThis","__CRUMB_BUNDLE_VERSION__","test","release","undefined","TypeError"],"sourceRoot":"../../src","sources":["build-release.ts"],"mappings":";;AAOA,OAAO,SAASA,gBAAgBA,CAC9BC,aAAiC,EACb;EACpB,MAAMC,aAAa,GAAGC,UAAU,CAACC,wBAAwB;EACzD,IACE,OAAOF,aAAa,KAAK,QAAQ,IACjC,CAAC,qCAAqC,CAACG,IAAI,CAACH,aAAa,CAAC,EAC1D;IACA,OAAOD,aAAa;EACtB;EACA,IACEA,aAAa,CAACK,OAAO,EAAEJ,aAAa,KAAKK,SAAS,IAClDN,aAAa,CAACK,OAAO,CAACJ,aAAa,KAAKA,aAAa,EACrD;IACA,MAAM,IAAIM,SAAS,CACjB,yIACF,CAAC;EACH;EACA,OAAO;IACL,GAAGP,aAAa;IAChBK,OAAO,EAAE;MAAE,GAAGL,aAAa,CAACK,OAAO;MAAEJ;IAAc;EACrD,CAAC;AACH","ignoreList":[]}
@@ -1,11 +1,13 @@
1
1
  "use strict";
2
2
 
3
3
  import NativeCrumbReactNative from './NativeCrumbReactNative';
4
+ import { withBuildRelease } from "./build-release.js";
4
5
  import { currentScreenJson, setScreen, trackReactNavigation, useExpoRouterScreen } from "./screen-context.js";
5
6
  export { setScreen, trackReactNavigation, useExpoRouterScreen };
6
7
  import { configureJavaScriptCrashCapture, recoverJavaScriptCrashes } from "./javascript-crash-capture.js";
7
8
  import { clearLogs, configureLogBuffer, disableConsoleCapture, enableConsoleCapture, markNativeStarted, writeLog } from "./log-buffer.js";
8
- export async function start(configuration) {
9
+ export async function start(input) {
10
+ const configuration = withBuildRelease(input);
9
11
  validateConfiguration(configuration);
10
12
  const logOptions = configuration.diagnostics?.logs;
11
13
  configureLogBuffer(logOptions);
@@ -1 +1 @@
1
- {"version":3,"names":["NativeCrumbReactNative","currentScreenJson","setScreen","trackReactNavigation","useExpoRouterScreen","configureJavaScriptCrashCapture","recoverJavaScriptCrashes","clearLogs","configureLogBuffer","disableConsoleCapture","enableConsoleCapture","markNativeStarted","writeLog","start","configuration","validateConfiguration","logOptions","diagnostics","logs","JSON","stringify","captureConsole","javascriptCrashCapture","enabled","installReporter","show","log","level","message","metadata","trim","TypeError","projectKey","environment","assertPositiveInteger","capture","maximumScreenshotDimension","maximumScreenshotBytes","timeoutMs","lookbackMs","maximumEntries","maximumBytes","renderingEnabled","undefined","assertJavaScriptCrashCapture","reporter","theme","includes","assertReporterFields","visibleFields","assertEvidence","evidence","assertApplicationMetadata","application","name","assertCustomContext","customContext","assertWorkspacePolicy","workspacePolicy","value","maximumBreadcrumbs","maximumBreadcrumbBytes","Set","size","length","some","field","supported","item","hasControlCharacters","allowedKeys","values","Array","isArray","key","isValidContextKey","entries","Object","url","URL","protocol","username","password","search","hash","test","character","Number","isSafeInteger","Crumb","freeze"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["NativeCrumbReactNative","withBuildRelease","currentScreenJson","setScreen","trackReactNavigation","useExpoRouterScreen","configureJavaScriptCrashCapture","recoverJavaScriptCrashes","clearLogs","configureLogBuffer","disableConsoleCapture","enableConsoleCapture","markNativeStarted","writeLog","start","input","configuration","validateConfiguration","logOptions","diagnostics","logs","JSON","stringify","captureConsole","javascriptCrashCapture","enabled","installReporter","show","log","level","message","metadata","trim","TypeError","projectKey","environment","assertPositiveInteger","capture","maximumScreenshotDimension","maximumScreenshotBytes","timeoutMs","lookbackMs","maximumEntries","maximumBytes","renderingEnabled","undefined","assertJavaScriptCrashCapture","reporter","theme","includes","assertReporterFields","visibleFields","assertEvidence","evidence","assertApplicationMetadata","application","name","assertCustomContext","customContext","assertWorkspacePolicy","workspacePolicy","value","maximumBreadcrumbs","maximumBreadcrumbBytes","Set","size","length","some","field","supported","item","hasControlCharacters","allowedKeys","values","Array","isArray","key","isValidContextKey","entries","Object","url","URL","protocol","username","password","search","hash","test","character","Number","isSafeInteger","Crumb","freeze"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,6 @@
1
+ import type { CrumbConfiguration } from './types.js';
2
+ declare global {
3
+ var __CRUMB_BUNDLE_VERSION__: unknown;
4
+ }
5
+ export declare function withBuildRelease(configuration: CrumbConfiguration): CrumbConfiguration;
6
+ //# sourceMappingURL=build-release.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-release.d.ts","sourceRoot":"","sources":["../../../src/build-release.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAS,CAAC;AAElD,OAAO,CAAC,MAAM,CAAC;IAEb,IAAI,wBAAwB,EAAE,OAAO,CAAC;CACvC;AAED,wBAAgB,gBAAgB,CAC9B,aAAa,EAAE,kBAAkB,GAChC,kBAAkB,CAoBpB"}
@@ -4,7 +4,7 @@ export type { CrumbScreenOptions, CrumbNavigationRef } from './screen-context.js
4
4
  import { clearLogs, disableConsoleCapture, enableConsoleCapture } from './log-buffer.js';
5
5
  import type { CrumbConfiguration, CrumbLogLevel, CrumbLogMetadata } from './types.js';
6
6
  export type { CrumbApplicationMetadata, CrumbCaptureOptions, CrumbConfiguration, CrumbCustomContextOptions, CrumbDiagnosticsOptions, CrumbJavaScriptCrashCaptureOptions, CrumbEvidenceCategory, CrumbInvocation, CrumbLogLevel, CrumbLogMetadata, CrumbLogOptions, CrumbPrivacyOptions, CrumbReporterField, CrumbReporterOptions, CrumbRelease, CrumbTheme, CrumbUploadOptions, CrumbWorkspacePolicyOptions, } from './types.js';
7
- export declare function start(configuration: CrumbConfiguration): Promise<void>;
7
+ export declare function start(input: CrumbConfiguration): Promise<void>;
8
8
  export declare function installReporter(): Promise<boolean>;
9
9
  export declare function show(): Promise<boolean>;
10
10
  export declare function log(level: CrumbLogLevel, message: string, metadata?: CrumbLogMetadata): void;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,SAAS,EACT,oBAAoB,EACpB,mBAAmB,EACpB,MAAM,qBAAkB,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,CAAC;AAChE,YAAY,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,qBAAkB,CAAC;AAK/E,OAAO,EACL,SAAS,EAET,qBAAqB,EACrB,oBAAoB,EAGrB,MAAM,iBAAc,CAAC;AACtB,OAAO,KAAK,EACV,kBAAkB,EAElB,aAAa,EACb,gBAAgB,EACjB,MAAM,YAAS,CAAC;AAEjB,YAAY,EACV,wBAAwB,EACxB,mBAAmB,EACnB,kBAAkB,EAClB,yBAAyB,EACzB,uBAAuB,EACvB,kCAAkC,EAClC,qBAAqB,EACrB,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,mBAAmB,EACnB,kBAAkB,EAClB,oBAAoB,EACpB,YAAY,EACZ,UAAU,EACV,kBAAkB,EAClB,2BAA2B,GAC5B,MAAM,YAAS,CAAC;AAEjB,wBAAsB,KAAK,CAAC,aAAa,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAoB5E;AAED,wBAAgB,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC,CAElD;AAED,wBAAgB,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC,CAEvC;AAED,wBAAgB,GAAG,CACjB,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,gBAAgB,GAC1B,IAAI,CAKN;AAED,OAAO,EAAE,SAAS,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,CAAC;AAoOlE,QAAA,MAAM,KAAK;;;;;;;;;;;EAWT,CAAC;AAEH,eAAe,KAAK,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,SAAS,EACT,oBAAoB,EACpB,mBAAmB,EACpB,MAAM,qBAAkB,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,CAAC;AAChE,YAAY,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,qBAAkB,CAAC;AAK/E,OAAO,EACL,SAAS,EAET,qBAAqB,EACrB,oBAAoB,EAGrB,MAAM,iBAAc,CAAC;AACtB,OAAO,KAAK,EACV,kBAAkB,EAElB,aAAa,EACb,gBAAgB,EACjB,MAAM,YAAS,CAAC;AAEjB,YAAY,EACV,wBAAwB,EACxB,mBAAmB,EACnB,kBAAkB,EAClB,yBAAyB,EACzB,uBAAuB,EACvB,kCAAkC,EAClC,qBAAqB,EACrB,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,mBAAmB,EACnB,kBAAkB,EAClB,oBAAoB,EACpB,YAAY,EACZ,UAAU,EACV,kBAAkB,EAClB,2BAA2B,GAC5B,MAAM,YAAS,CAAC;AAEjB,wBAAsB,KAAK,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqBpE;AAED,wBAAgB,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC,CAElD;AAED,wBAAgB,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC,CAEvC;AAED,wBAAgB,GAAG,CACjB,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,gBAAgB,GAC1B,IAAI,CAKN;AAED,OAAO,EAAE,SAAS,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,CAAC;AAoOlE,QAAA,MAAM,KAAK;;;;;;;;;;;EAWT,CAAC;AAEH,eAAe,KAAK,CAAC"}
package/metro.cjs ADDED
@@ -0,0 +1,35 @@
1
+ const { readRelease } = require('./tools/release.cjs');
2
+
3
+ /** Preserve existing Metro options and include non-secret release metadata before app startup. */
4
+ function withCrumb(config) {
5
+ if (typeof config === 'function')
6
+ return (...args) => withCrumb(config(...args));
7
+ if (config && typeof config.then === 'function')
8
+ return config.then(withCrumb);
9
+ if (!config || typeof config !== 'object')
10
+ throw new Error('Pass your existing Metro configuration to withCrumb.');
11
+ const manifest = process.env.CRUMB_RELEASE_MANIFEST;
12
+ if (!manifest) return config;
13
+ const release = readRelease(manifest);
14
+ const getPolyfills = config.serializer?.getPolyfills;
15
+ return {
16
+ ...config,
17
+ serializer: {
18
+ ...config.serializer,
19
+ getPolyfills: (...args) => [
20
+ ...new Set([
21
+ ...(getPolyfills ? getPolyfills(...args) : []),
22
+ release.polyfill,
23
+ ]),
24
+ ],
25
+ },
26
+ watchFolders: [
27
+ ...new Set([
28
+ ...(config.watchFolders || []),
29
+ require('node:path').dirname(release.polyfill),
30
+ ]),
31
+ ],
32
+ };
33
+ }
34
+
35
+ module.exports = { withCrumb };
package/metro.d.cts ADDED
@@ -0,0 +1,2 @@
1
+ /** Wrap an existing object, async, or function Metro configuration without replacing its options. */
2
+ export function withCrumb<T extends object>(config: T): T;
@@ -1 +1 @@
1
- 0.0.1-rc.4
1
+ 0.0.1-rc.5
@@ -24,7 +24,7 @@ public enum Crumb {
24
24
  settings.diagnostics.javascriptCrashCaptureEnabled else {
25
25
  return
26
26
  }
27
- _ = CrumbJavaScriptCrashStore.shared.record(recordJSON, failureContext: CrumbJavaScriptFailureContext.capture(settings: settings), includeBreadcrumbs: settings.diagnostics.logs.enabled && settings.evidence.contains(.logs))
27
+ _ = CrumbJavaScriptCrashStore.shared.record(recordJSON, failureContext: CrumbJavaScriptFailureContext.capture(settings: settings), includeBreadcrumbs: settings.diagnostics.logs.enabled && settings.evidence.contains(.logs), release: settings.release)
28
28
  }
29
29
 
30
30
  /// Moves pending JavaScript failures into the regular durable report queue.
@@ -22,7 +22,7 @@ package struct CrumbJavaScriptCrash: Equatable, Sendable {
22
22
  package let message: String
23
23
  package let stack: String?
24
24
  package let occurredAt: Date
25
- package let release: CrumbJavaScriptCrashRelease
25
+ package var release: CrumbJavaScriptCrashRelease
26
26
  package var breadcrumbs: [CrumbJavaScriptBreadcrumb]
27
27
  package let context: [String: String]
28
28
  package let isFatal: Bool
@@ -80,7 +80,7 @@ package final class CrumbJavaScriptCrashStore: @unchecked Sendable {
80
80
  }
81
81
 
82
82
  @discardableResult
83
- package func record(_ recordJSON: String, failureContext: CrumbJavaScriptFailureContext? = nil, includeBreadcrumbs: Bool = true) -> Bool {
83
+ package func record(_ recordJSON: String, failureContext: CrumbJavaScriptFailureContext? = nil, includeBreadcrumbs: Bool = true, release: CrumbRelease? = nil) -> Bool {
84
84
  lock.lock()
85
85
  defer { lock.unlock() }
86
86
 
@@ -94,6 +94,12 @@ package final class CrumbJavaScriptCrashStore: @unchecked Sendable {
94
94
 
95
95
  // The JS payload cannot supply native context. Only the trusted capture argument can.
96
96
  record.failureContext = failureContext?.validated()
97
+ // Freeze native defaults at failure time, before a later app update can change them.
98
+ record.release = CrumbJavaScriptCrashRelease(
99
+ appVersion: record.release.appVersion ?? release?.appVersion,
100
+ nativeBuild: record.release.nativeBuild ?? release?.nativeBuild,
101
+ bundleVersion: record.release.bundleVersion ?? release?.bundleVersion
102
+ )
97
103
  if !includeBreadcrumbs { record.breadcrumbs = [] }
98
104
 
99
105
  do {
@@ -1,5 +1,5 @@
1
1
  // Generated from the repository VERSION file. Do not edit by hand.
2
2
 
3
3
  public enum CrumbSDKVersion {
4
- public static let current = "0.0.1-rc.4"
4
+ public static let current = "0.0.1-rc.5"
5
5
  }
@@ -1,5 +1,5 @@
1
1
  {
2
- "nativeVersion": "0.0.1-rc.4",
2
+ "nativeVersion": "0.0.1-rc.5",
3
3
  "PLCrashReporter": {
4
4
  "version": "1.12.0",
5
5
  "url": "https://github.com/microsoft/plcrashreporter/releases/download/1.12.0/PLCrashReporter-Static-1.12.0.xcframework.zip",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crumbsdk/react-native",
3
- "version": "0.0.1-rc.4",
3
+ "version": "0.0.1-rc.5",
4
4
  "description": "React Native adapter for the native Crumb issue-reporting SDK",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",
@@ -11,7 +11,11 @@
11
11
  "default": "./lib/module/index.js"
12
12
  },
13
13
  "./package.json": "./package.json",
14
- "./app.plugin.js": "./app.plugin.js"
14
+ "./app.plugin.js": "./app.plugin.js",
15
+ "./metro": {
16
+ "types": "./metro.d.cts",
17
+ "default": "./metro.cjs"
18
+ }
15
19
  },
16
20
  "files": [
17
21
  "src",
@@ -31,7 +35,10 @@
31
35
  "native",
32
36
  "scripts/ios.rb",
33
37
  "app.plugin.js",
34
- "plugin"
38
+ "plugin",
39
+ "metro.cjs",
40
+ "tools",
41
+ "metro.d.cts"
35
42
  ],
36
43
  "scripts": {
37
44
  "example": "yarn workspace @crumbsdk/react-native-example",
@@ -72,7 +79,7 @@
72
79
  "access": "public",
73
80
  "registry": "https://registry.npmjs.org/"
74
81
  },
75
- "crumbNativeVersion": "0.0.1-rc.4",
82
+ "crumbNativeVersion": "0.0.1-rc.5",
76
83
  "devDependencies": {
77
84
  "@babel/core": "7.29.7",
78
85
  "@eslint/compat": "2.1.0",
@@ -144,5 +151,12 @@
144
151
  "jest"
145
152
  ],
146
153
  "version": "0.63.0"
154
+ },
155
+ "dependencies": {
156
+ "@crumbsdk/source-maps": "0.0.1-rc.4",
157
+ "xcode": "3.0.1"
158
+ },
159
+ "bin": {
160
+ "crumb": "tools/cli.cjs"
147
161
  }
148
162
  }
@@ -0,0 +1,52 @@
1
+ const marker = 'crumb-release-build';
2
+
3
+ function shellQuote(value) {
4
+ return `'${value.replaceAll("'", "'\\''")}'`;
5
+ }
6
+
7
+ function configureXcodeProject(project) {
8
+ let found = false;
9
+ for (const phase of Object.values(
10
+ project.hash.project.objects.PBXShellScriptBuildPhase || {}
11
+ )) {
12
+ if (!phase || typeof phase.shellScript !== 'string') continue;
13
+ // Expo mods can supply literal control characters inside the quoted PBX value.
14
+ const original = phase.shellScript.startsWith('"')
15
+ ? JSON.parse(
16
+ phase.shellScript
17
+ .replaceAll('\n', '\\n')
18
+ .replaceAll('\r', '\\r')
19
+ .replaceAll('\t', '\\t')
20
+ )
21
+ : phase.shellScript;
22
+ if (original.includes(marker)) {
23
+ found = true;
24
+ continue;
25
+ }
26
+ if (!original.includes('react-native-xcode.sh')) continue;
27
+ const wrapper = `# ${marker}
28
+ set -e
29
+ if [ -f "$PODS_ROOT/../.xcode.env" ]; then . "$PODS_ROOT/../.xcode.env"; fi
30
+ if [ -f "$PODS_ROOT/../.xcode.env.local" ]; then . "$PODS_ROOT/../.xcode.env.local"; fi
31
+ NODE_BINARY="\${NODE_BINARY:-node}"
32
+ CRUMB_PACKAGE_DIR="$("$NODE_BINARY" --print "require('path').dirname(require.resolve('@crumbsdk/react-native/package.json'))")"
33
+ "$NODE_BINARY" "$CRUMB_PACKAGE_DIR/tools/ios.cjs" /bin/bash -c ${shellQuote(original)}
34
+ `;
35
+ phase.shellScript = JSON.stringify(wrapper);
36
+ // The original native script and the wrapper own their incremental outputs.
37
+ phase.alwaysOutOfDate = 1;
38
+ found = true;
39
+ }
40
+ if (!found)
41
+ throw new Error(
42
+ 'Crumb could not locate the React Native Xcode bundle phase. See the manual build-hook instructions.'
43
+ );
44
+ return project;
45
+ }
46
+
47
+ function configureGradle(contents) {
48
+ if (contents.includes(marker)) return contents;
49
+ return `${contents}\n// ${marker}\napply from: new File(["node", "--print", "require.resolve('@crumbsdk/react-native/package.json')"].execute(null, rootDir).text.trim()).parentFile.toPath().resolve("tools/crumb.gradle").toFile()\n`;
50
+ }
51
+
52
+ module.exports = { configureXcodeProject, configureGradle };
@@ -0,0 +1,30 @@
1
+ import type { CrumbConfiguration } from './types';
2
+
3
+ declare global {
4
+ // Written by the release build polyfill before application modules execute.
5
+ var __CRUMB_BUNDLE_VERSION__: unknown;
6
+ }
7
+
8
+ export function withBuildRelease(
9
+ configuration: CrumbConfiguration
10
+ ): CrumbConfiguration {
11
+ const bundleVersion = globalThis.__CRUMB_BUNDLE_VERSION__;
12
+ if (
13
+ typeof bundleVersion !== 'string' ||
14
+ !/^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$/.test(bundleVersion)
15
+ ) {
16
+ return configuration;
17
+ }
18
+ if (
19
+ configuration.release?.bundleVersion !== undefined &&
20
+ configuration.release.bundleVersion !== bundleVersion
21
+ ) {
22
+ throw new TypeError(
23
+ 'Crumb release.bundleVersion conflicts with the generated build identity. Remove the manual value or disable automatic source-map setup.'
24
+ );
25
+ }
26
+ return {
27
+ ...configuration,
28
+ release: { ...configuration.release, bundleVersion },
29
+ };
30
+ }
package/src/index.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import NativeCrumbReactNative from './NativeCrumbReactNative';
2
+ import { withBuildRelease } from './build-release';
2
3
  import {
3
4
  currentScreenJson,
4
5
  setScreen,
@@ -47,7 +48,8 @@ export type {
47
48
  CrumbWorkspacePolicyOptions,
48
49
  } from './types';
49
50
 
50
- export async function start(configuration: CrumbConfiguration): Promise<void> {
51
+ export async function start(input: CrumbConfiguration): Promise<void> {
52
+ const configuration = withBuildRelease(input);
51
53
  validateConfiguration(configuration);
52
54
  const logOptions = configuration.diagnostics?.logs;
53
55
  configureLogBuffer(logOptions);
package/tools/cli.cjs ADDED
@@ -0,0 +1,116 @@
1
+ #!/usr/bin/env node
2
+ const fs = require('node:fs');
3
+ const path = require('node:path');
4
+ const { parseArgs } = require('node:util');
5
+ const { createInterface } = require('node:readline/promises');
6
+ const { setupPlan, applyPlan, doctor } = require('./setup.cjs');
7
+ const { prepareRelease } = require('./release.cjs');
8
+ const { uploadRelease, retryUpload } = require('./upload.cjs');
9
+
10
+ async function main() {
11
+ if (Number(process.versions.node.split('.')[0]) < 22)
12
+ throw new Error('Crumb build tooling requires Node.js 22 or newer.');
13
+ const { positionals, values } = parseArgs({
14
+ allowPositionals: true,
15
+ options: {
16
+ help: { type: 'boolean' },
17
+ apply: { type: 'boolean' },
18
+ 'source-maps': { type: 'boolean' },
19
+ 'upload-url': { type: 'string' },
20
+ root: { type: 'string' },
21
+ directory: { type: 'string' },
22
+ input: { type: 'string' },
23
+ receipt: { type: 'string' },
24
+ output: { type: 'string' },
25
+ targets: { type: 'string' },
26
+ 'dry-run': { type: 'boolean' },
27
+ },
28
+ });
29
+ const root = path.resolve(values.root || process.cwd());
30
+ const [command] = positionals;
31
+ if (values.help || !command) {
32
+ console.log(
33
+ 'crumb setup [--source-maps --upload-url HTTPS_ORIGIN] [--apply]\ncrumb doctor\ncrumb retry --receipt FILE\ncrumb export --output DIRECTORY --targets FILE [--dry-run]\n\nSetup previews changes; --apply accepts them without prompting. Upload credentials belong only in CRUMB_SOURCE_MAP_TOKEN.'
34
+ );
35
+ return;
36
+ }
37
+ if (command === 'setup') {
38
+ let sourceMaps = values['source-maps'];
39
+ let uploadUrl = values['upload-url'];
40
+ const prompt =
41
+ process.stdin.isTTY && !values.apply
42
+ ? createInterface({ input: process.stdin, output: process.stdout })
43
+ : undefined;
44
+ try {
45
+ if (prompt && sourceMaps === undefined)
46
+ sourceMaps = /^y(es)?$/i.test(
47
+ await prompt.question(
48
+ 'Configure source maps for opt-in JavaScript crashes? [y/N] '
49
+ )
50
+ );
51
+ if (prompt && sourceMaps && !uploadUrl)
52
+ uploadUrl = await prompt.question(
53
+ 'Upload origin from your Crumb integration page: '
54
+ );
55
+ const plan = setupPlan(root, { sourceMaps, uploadUrl });
56
+ console.log(`Crumb setup: ${plan.framework}`);
57
+ for (const change of plan.changes)
58
+ console.log(
59
+ `- ${change.before === undefined ? 'Create' : 'Update'} ${change.name}`
60
+ );
61
+ console.log(
62
+ 'Setup adds Crumb configuration, preserves existing settings, and wraps supported build hooks. Review the resulting diff before committing.'
63
+ );
64
+ if (
65
+ values.apply ||
66
+ (prompt &&
67
+ /^y(es)?$/i.test(
68
+ await prompt.question(
69
+ `Apply ${plan.changes.length} reviewed file changes? [y/N] `
70
+ )
71
+ ))
72
+ ) {
73
+ applyPlan(plan);
74
+ console.log('Setup changes applied.');
75
+ } else
76
+ console.log(
77
+ 'Preview only. Run again with --apply to apply these changes.'
78
+ );
79
+ for (const instruction of plan.instructions)
80
+ console.log(`- ${instruction}`);
81
+ } finally {
82
+ prompt?.close();
83
+ }
84
+ } else if (command === 'doctor') {
85
+ const result = doctor(root);
86
+ console.log(JSON.stringify(result, null, 2));
87
+ if (result.checks.some((check) => check.status === 'missing'))
88
+ process.exitCode = 1;
89
+ } else if (command === 'prepare' && values.directory) {
90
+ prepareRelease(path.resolve(values.directory));
91
+ } else if (command === 'upload-build' && values.input) {
92
+ uploadRelease(JSON.parse(fs.readFileSync(values.input, 'utf8')), {
93
+ dryRun: values['dry-run'],
94
+ });
95
+ } else if (command === 'export' && values.output && values.targets) {
96
+ require('./expo-export.cjs').exportRelease(
97
+ root,
98
+ values.output,
99
+ values.targets,
100
+ { dryRun: values['dry-run'] }
101
+ );
102
+ } else if (command === 'retry' && values.receipt) {
103
+ retryUpload(values.receipt);
104
+ } else
105
+ throw new Error('Unknown or incomplete Crumb command. Run crumb --help.');
106
+ }
107
+
108
+ main().catch((error) => {
109
+ const message =
110
+ error instanceof SyntaxError ||
111
+ String(error.code).startsWith('ERR_PARSE_ARGS')
112
+ ? 'Invalid command or JSON input. Run crumb --help; keep credentials only in the build environment.'
113
+ : error.message;
114
+ console.error(`Crumb: ${message}`);
115
+ process.exitCode = 1;
116
+ });
@@ -0,0 +1,72 @@
1
+ const fs = require('node:fs');
2
+ const path = require('node:path');
3
+
4
+ function readConfig(root) {
5
+ const file = path.join(root, 'crumb.config.json');
6
+ if (!fs.existsSync(file))
7
+ return { version: 1, sourceMaps: { enabled: false } };
8
+ let config;
9
+ try {
10
+ config = JSON.parse(fs.readFileSync(file, 'utf8'));
11
+ } catch {
12
+ throw new Error(
13
+ 'Could not read crumb.config.json. Check that it contains valid JSON without credentials.'
14
+ );
15
+ }
16
+ if (
17
+ !config ||
18
+ typeof config !== 'object' ||
19
+ Array.isArray(config) ||
20
+ config.version !== 1 ||
21
+ !config.sourceMaps ||
22
+ typeof config.sourceMaps !== 'object' ||
23
+ Array.isArray(config.sourceMaps) ||
24
+ Object.keys(config).some(
25
+ (key) => !['version', 'sourceMaps'].includes(key)
26
+ ) ||
27
+ Object.keys(config.sourceMaps).some(
28
+ (key) => !['enabled', 'uploadUrl', 'strict'].includes(key)
29
+ ) ||
30
+ typeof config.sourceMaps.enabled !== 'boolean' ||
31
+ (config.sourceMaps.strict !== undefined &&
32
+ typeof config.sourceMaps.strict !== 'boolean')
33
+ ) {
34
+ throw new Error(
35
+ 'Invalid crumb.config.json. Use crumb setup; keep credentials only in the build environment.'
36
+ );
37
+ }
38
+ if (config.sourceMaps.enabled) validateOrigin(config.sourceMaps.uploadUrl);
39
+ return config;
40
+ }
41
+
42
+ function validateOrigin(value) {
43
+ let url;
44
+ try {
45
+ url = new URL(value);
46
+ } catch {
47
+ throw new Error(
48
+ 'Supply the HTTPS upload origin shown in your Crumb integration instructions.'
49
+ );
50
+ }
51
+ if (
52
+ url.protocol !== 'https:' ||
53
+ url.username ||
54
+ url.password ||
55
+ url.search ||
56
+ url.hash ||
57
+ url.pathname !== '/'
58
+ ) {
59
+ throw new Error(
60
+ 'The upload origin must use HTTPS without a path, credentials, query, or fragment.'
61
+ );
62
+ }
63
+ return url.origin;
64
+ }
65
+
66
+ function isStrict(config, env = process.env) {
67
+ return (
68
+ env.CRUMB_SOURCE_MAP_STRICT === '1' || config.sourceMaps.strict === true
69
+ );
70
+ }
71
+
72
+ module.exports = { readConfig, validateOrigin, isStrict };