pulse-updates 1.3.7 → 1.3.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.
@@ -1 +1 @@
1
- {"version":3,"file":"links.d.ts","sourceRoot":"","sources":["../../src/links.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"links.d.ts","sourceRoot":"","sources":["../../src/links.ts"],"names":[],"mappings":"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"}
@@ -45,7 +45,7 @@ export interface TrackOptions {
45
45
  flushIntervalMs?: number;
46
46
  /** Events per request. The server refuses more than 100. */
47
47
  maxBatch?: number;
48
- /** Events held before the oldest are dropped. Default 500. */
48
+ /** Best-effort events held before the oldest are dropped. Durable idempotent rows are never evicted. Default 500. */
49
49
  maxQueue?: number;
50
50
  /** Persists the outbox across process death. Use the same storage passed to initPulse. */
51
51
  storage?: ConfigStorage;
@@ -53,9 +53,12 @@ export interface TrackOptions {
53
53
  storageKey?: string;
54
54
  /** Per-request timeout. Default 10s. */
55
55
  timeoutMs?: number;
56
- /** Maximum delivery attempts before an event is dropped. Default 10. */
56
+ /** Maximum delivery attempts before a best-effort event is dropped. Durable idempotent events retry until server ACK. Default 10. */
57
57
  maxAttempts?: number;
58
- /** Return false until analytics consent exists. No event is retained before consent. */
58
+ /**
59
+ * Return false until analytics consent exists. No event is retained before consent. Consent is
60
+ * sampled at enqueue; an event already durably accepted remains eligible for later delivery.
61
+ */
59
62
  hasConsent?: () => boolean;
60
63
  /** Only these property keys may leave the process. */
61
64
  propertyAllowlist?: readonly string[];
@@ -84,12 +87,20 @@ export declare function configureTracking(opts: TrackOptions): void;
84
87
  * caller has to wrap.
85
88
  */
86
89
  export declare function track(event: string, props?: TrackedEventInput['props'], time?: Date): void;
90
+ /**
91
+ * Durably enqueue one logical event with a caller-owned UUID. Replaying the same id is safe:
92
+ * Pulse's server/read model deduplicates it, while the local outbox avoids duplicate rows that
93
+ * are still pending. `true` means the event is present in persistent storage, not delivered yet;
94
+ * once acknowledged, Track keeps it in that outbox through retries and process restarts until a
95
+ * successful server response removes it transactionally.
96
+ */
97
+ export declare function trackIdempotent(eventId: string, event: string, props?: TrackedEventInput['props'], time?: Date): boolean;
87
98
  /**
88
99
  * Send what is queued. Returns how many events the server accepted.
89
100
  *
90
- * Failures put the batch back at the front of the queue rather than dropping it: the
91
- * usual cause is a network that is about to come back, and the usual moment is right
92
- * after launch, when the first events of a session are the ones a funnel needs most.
101
+ * The batch remains in the durable queue while HTTP is in flight and is removed only after a
102
+ * successful response is also persisted locally. This intentionally permits duplicate replay
103
+ * after a crash, while a caller-owned event id lets the server/read model deduplicate it.
93
104
  */
94
105
  export declare function flushEvents(): Promise<number>;
95
106
  /** How many events are waiting — for a caller that wants to flush before backgrounding. */
@@ -1 +1 @@
1
- {"version":3,"file":"track.d.ts","sourceRoot":"","sources":["../../src/track.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE7D,MAAM,WAAW,YAAY;IAC3B;;;;;OAKG;IACH,GAAG,EAAE,MAAM,CAAC;IAEZ;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,aAAa,CAAC;IAEjC;;;;;OAKG;IACH,YAAY,CAAC,EAAE,SAAS,GAAG,wBAAwB,CAAC;IAEpD,wDAAwD;IACxD,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,0FAA0F;IAC1F,OAAO,CAAC,EAAE,aAAa,CAAC;IAExB,wEAAwE;IACxE,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,wCAAwC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,wEAAwE;IACxE,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,wFAAwF;IACxF,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC;IAE3B,sDAAsD;IACtD,iBAAiB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAEtC,+DAA+D;IAC/D,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAErC,0EAA0E;IAC1E,QAAQ,CAAC,EAAE;QAAE,gBAAgB,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,KAAK;YAAE,MAAM,EAAE,MAAM,IAAI,CAAA;SAAE,CAAA;KAAE,CAAC;IAE9G,+DAA+D;IAC/D,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAEvC,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,cAAc,GAAG,YAAY,KAAK,IAAI,CAAC;IAE1F,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACpC;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IACrE,IAAI,CAAC,EAAE,IAAI,CAAC;CACb;AAoCD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CAY1D;AAED;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,iBAAiB,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CA2B1F;AAED;;;;;;GAMG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC,CAiEnD;AAED,2FAA2F;AAC3F,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED,wBAAgB,eAAe,IAAI;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;CACvB,CAEA;AAED,qEAAqE;AACrE,wBAAgB,eAAe,IAAI,IAAI,CAStC;AAED,wBAAgB,YAAY,IAAI,IAAI,CAOnC"}
1
+ {"version":3,"file":"track.d.ts","sourceRoot":"","sources":["../../src/track.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE7D,MAAM,WAAW,YAAY;IAC3B;;;;;OAKG;IACH,GAAG,EAAE,MAAM,CAAC;IAEZ;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,aAAa,CAAC;IAEjC;;;;;OAKG;IACH,YAAY,CAAC,EAAE,SAAS,GAAG,wBAAwB,CAAC;IAEpD,wDAAwD;IACxD,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,qHAAqH;IACrH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,0FAA0F;IAC1F,OAAO,CAAC,EAAE,aAAa,CAAC;IAExB,wEAAwE;IACxE,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,wCAAwC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,qIAAqI;IACrI,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC;IAE3B,sDAAsD;IACtD,iBAAiB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAEtC,+DAA+D;IAC/D,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAErC,0EAA0E;IAC1E,QAAQ,CAAC,EAAE;QAAE,gBAAgB,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,KAAK;YAAE,MAAM,EAAE,MAAM,IAAI,CAAA;SAAE,CAAA;KAAE,CAAC;IAE9G,+DAA+D;IAC/D,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAEvC,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,cAAc,GAAG,YAAY,KAAK,IAAI,CAAC;IAE1F,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACpC;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IACrE,IAAI,CAAC,EAAE,IAAI,CAAC;CACb;AAuCD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CAY1D;AAED;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,iBAAiB,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAE1F;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,KAAK,CAAC,EAAE,iBAAiB,CAAC,OAAO,CAAC,EAClC,IAAI,CAAC,EAAE,IAAI,GACV,OAAO,CAIT;AA2GD;;;;;;GAMG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC,CAiEnD;AAED,2FAA2F;AAC3F,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED,wBAAgB,eAAe,IAAI;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;CACvB,CAEA;AAED,qEAAqE;AACrE,wBAAgB,eAAe,IAAI,IAAI,CAStC;AAED,wBAAgB,YAAY,IAAI,IAAI,CAOnC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pulse-updates",
3
- "version": "1.3.7",
3
+ "version": "1.3.9",
4
4
  "description": "Pulse app-experience SDK for React Native: updates, config, experiments, events, decisions and first-party links",
5
5
  "main": "lib/commonjs/index.js",
6
6
  "module": "lib/module/index.js",
@@ -54,7 +54,9 @@
54
54
  "react-native": ">=0.76.0"
55
55
  },
56
56
  "peerDependenciesMeta": {
57
- "@expo/config-plugins": { "optional": true }
57
+ "@expo/config-plugins": {
58
+ "optional": true
59
+ }
58
60
  },
59
61
  "dependencies": {
60
62
  "tweetnacl": "1.0.3"
@@ -119,6 +119,122 @@ async function hashFileSHA256(filePath) {
119
119
  });
120
120
  }
121
121
 
122
+ const NATIVE_MODULE_EVIDENCE_VERSION = 1;
123
+ const NATIVE_MODULE_NAME = /^[\w.$-]{1,128}$/;
124
+ const SHA256_HEX = /^[0-9a-f]{64}$/;
125
+
126
+ function validateNativeModules(value, source) {
127
+ if (!Array.isArray(value) || value.length > 4096) {
128
+ throw new Error(`Invalid native-module evidence in ${source}: nativeModules must be an array`);
129
+ }
130
+ if (!value.every((name) => typeof name === 'string' && NATIVE_MODULE_NAME.test(name))) {
131
+ throw new Error(`Invalid native-module evidence in ${source}: nativeModules contains an invalid name`);
132
+ }
133
+ const canonical = [...new Set(value)].sort();
134
+ if (canonical.length !== value.length || canonical.some((name, index) => name !== value[index])) {
135
+ throw new Error(`Invalid native-module evidence in ${source}: nativeModules must be sorted and unique`);
136
+ }
137
+ return [...value];
138
+ }
139
+
140
+ function validateEvidenceContext(value, config, source) {
141
+ if (value.schemaVersion !== NATIVE_MODULE_EVIDENCE_VERSION
142
+ || value.platform !== config.platform
143
+ || value.runtimeVersion !== config.runtimeVersion
144
+ || value.channel !== config.channel) {
145
+ throw new Error(
146
+ `Invalid native-module evidence in ${source}: release context does not match ` +
147
+ `${config.runtimeVersion}/${config.platform}/${config.channel}`
148
+ );
149
+ }
150
+ if (!SHA256_HEX.test(value.scannedBundleSha256 ?? '')
151
+ || !SHA256_HEX.test(value.uploadBundleSha256 ?? '')) {
152
+ throw new Error(`Invalid native-module evidence in ${source}: bundle SHA-256 is missing or invalid`);
153
+ }
154
+ }
155
+
156
+ /**
157
+ * Persist the capability scan beside a hash of the exact post-Hermes artifact. A wrapper that
158
+ * deliberately transforms that artifact (for example Bastion) must first verify
159
+ * scannedBundleSha256, then replace uploadBundleSha256 with the transformed artifact hash. The
160
+ * --skip-bundle pass verifies the latter before it creates anything server-side.
161
+ */
162
+ export async function writeNativeModulesEvidence(evidencePath, config, bundlePath, nativeModules) {
163
+ const resolved = path.resolve(evidencePath);
164
+ const canonicalModules = validateNativeModules(nativeModules, resolved);
165
+ const bundleSha256 = await hashFileSHA256(bundlePath);
166
+ const evidence = {
167
+ schemaVersion: NATIVE_MODULE_EVIDENCE_VERSION,
168
+ platform: config.platform,
169
+ runtimeVersion: config.runtimeVersion,
170
+ channel: config.channel,
171
+ scannedBundleSha256: bundleSha256,
172
+ uploadBundleSha256: bundleSha256,
173
+ nativeModules: canonicalModules,
174
+ };
175
+ fs.mkdirSync(path.dirname(resolved), { recursive: true });
176
+ const temporary = `${resolved}.${process.pid}.${crypto.randomBytes(4).toString('hex')}.tmp`;
177
+ try {
178
+ fs.writeFileSync(temporary, `${JSON.stringify(evidence)}\n`, { mode: 0o600 });
179
+ fs.renameSync(temporary, resolved);
180
+ } finally {
181
+ // renameSync removes the source on success. On every failure path, including a destination
182
+ // that becomes invalid concurrently, do not strand capability evidence in a readable temp file.
183
+ try { fs.unlinkSync(temporary); } catch (error) {
184
+ if (error?.code !== 'ENOENT') throw error;
185
+ }
186
+ }
187
+ return evidence;
188
+ }
189
+
190
+ /** Read and bind capability evidence to the exact artifact about to be uploaded. */
191
+ export async function readNativeModulesEvidence(evidencePath, config, bundlePath) {
192
+ const resolved = path.resolve(evidencePath);
193
+ let evidence;
194
+ try {
195
+ evidence = JSON.parse(fs.readFileSync(resolved, 'utf8'));
196
+ } catch (error) {
197
+ throw new Error(`Native-module evidence is missing or unreadable at ${resolved}: ${error.message}`);
198
+ }
199
+ if (!evidence || typeof evidence !== 'object' || Array.isArray(evidence)) {
200
+ throw new Error(`Invalid native-module evidence in ${resolved}: expected an object`);
201
+ }
202
+ validateEvidenceContext(evidence, config, resolved);
203
+ const nativeModules = validateNativeModules(evidence.nativeModules, resolved);
204
+ const uploadBundleSha256 = await hashFileSHA256(bundlePath);
205
+ if (uploadBundleSha256 !== evidence.uploadBundleSha256) {
206
+ throw new Error(
207
+ `Native-module evidence does not describe the upload artifact: expected ` +
208
+ `${evidence.uploadBundleSha256}, got ${uploadBundleSha256}`
209
+ );
210
+ }
211
+ return { ...evidence, nativeModules };
212
+ }
213
+
214
+ export function createReleaseRequest(config, metadata, nativeModules, nativeModulesVerified) {
215
+ return {
216
+ runtimeVersion: config.runtimeVersion,
217
+ platform: config.platform,
218
+ channel: config.channel,
219
+ metadata: Object.keys(metadata).length > 0 ? metadata : undefined,
220
+ // A verified empty array is evidence too. Legacy --skip-bundle calls without the handoff file
221
+ // retain their old omitted-field behaviour, while guarded wrappers cannot silently bypass ABI
222
+ // preflight by turning a real scan into an absent fingerprint.
223
+ nativeModules: nativeModulesVerified
224
+ ? nativeModules
225
+ : (nativeModules.length ? nativeModules : undefined),
226
+ // Which binary this bundle is for, when it is only for one. A runtime version is not always a
227
+ // single build — on iOS it is MARKETING_VERSION, which stays put across re-submissions — and a
228
+ // bundle wrapped with one build's key cannot be opened by another, which stops that app from
229
+ // starting rather than merely leaving it un-updated. Naming the build keeps the manifest from
230
+ // handing it to the wrong one. Omitted for unwrapped bundles, which every build can load.
231
+ // Spread rather than assign: an explicit `nativeBuild: undefined` is invisible over the wire
232
+ // but not to a caller comparing the request it built, and unwrapped bundles have no build to
233
+ // name.
234
+ ...(config.nativeBuild ? { nativeBuild: config.nativeBuild } : {}),
235
+ };
236
+ }
237
+
122
238
  /**
123
239
  * Calculate MD5 hash of a file (for asset key - matches Metro/expo format)
124
240
  */
@@ -826,6 +942,10 @@ function loadConfig(options) {
826
942
  apiKey: options['api-key'] || process.env.PULSE_API_KEY || fileConfig.apiKey,
827
943
  runtimeVersion,
828
944
  platform,
945
+ // Only ever what the operator states. It could be read from the pbxproj or build.gradle, but a
946
+ // guess here is the failure it exists to prevent: the checkout is not reliably the build the
947
+ // update is for, which is the whole reason a runtime version is not enough on its own.
948
+ nativeBuild: options['native-build'] || process.env.PULSE_NATIVE_BUILD || fileConfig.nativeBuild,
829
949
  channel: options.channel || fileConfig.channel || 'production',
830
950
  bundleDir: options['bundle-dir'] || fileConfig.bundleDir || './dist',
831
951
  entryFile: options['entry-file'] || fileConfig.entryFile || 'index.ts',
@@ -844,7 +964,7 @@ function loadConfig(options) {
844
964
  /**
845
965
  * Main publish command
846
966
  */
847
- async function publish(options) {
967
+ export async function publish(options) {
848
968
  const config = loadConfig(options);
849
969
 
850
970
  // Validate required config
@@ -873,25 +993,60 @@ async function publish(options) {
873
993
  log(`Bundle Dir: ${bundleDir}\n`);
874
994
 
875
995
  let nativeModules = [];
996
+ let nativeModulesVerified = false;
997
+ const nativeModulesFileOption = options['native-modules-file'];
998
+ if (nativeModulesFileOption !== undefined
999
+ && (typeof nativeModulesFileOption !== 'string' || !nativeModulesFileOption.trim())) {
1000
+ throw new Error('--native-modules-file requires a path');
1001
+ }
1002
+ const nativeModulesFile = nativeModulesFileOption
1003
+ ? path.resolve(nativeModulesFileOption)
1004
+ : null;
1005
+ const bundlePath = path.join(bundleDir, config.platform, 'index.bundle');
876
1006
 
877
1007
  // Step 1: Create bundle (unless skipped)
878
1008
  if (!config.skipBundle) {
879
1009
  logStep('1/6', 'Creating bundle...');
880
- const bundlePath = createBundle(config.platform, bundleDir, config.entryFile);
881
- logSuccess(`Bundle created: ${bundlePath}`);
1010
+ const createdBundlePath = createBundle(config.platform, bundleDir, config.entryFile);
1011
+ logSuccess(`Bundle created: ${createdBundlePath}`);
882
1012
 
883
1013
  // Crash-prediction fingerprint: extract native module references from the plain JS bundle
884
1014
  // (must happen BEFORE Hermes bytecode compilation, while the bundle is still readable JS).
885
- nativeModules = extractNativeModules(bundlePath);
1015
+ nativeModules = extractNativeModules(createdBundlePath);
1016
+ nativeModulesVerified = true;
886
1017
  log(`Native modules referenced: ${nativeModules.length}${nativeModules.length ? ` (${nativeModules.join(', ')})` : ''}`);
887
1018
 
888
1019
  // Step 2: Compile with Hermes
889
1020
  logStep('2/6', 'Compiling with Hermes...');
890
- compileWithHermes(bundlePath, config.platform, { requireHermes: config.requireHermes });
1021
+ compileWithHermes(createdBundlePath, config.platform, { requireHermes: config.requireHermes });
891
1022
  logSuccess('Hermes compilation complete');
1023
+ if (nativeModulesFile) {
1024
+ await writeNativeModulesEvidence(
1025
+ nativeModulesFile,
1026
+ config,
1027
+ createdBundlePath,
1028
+ nativeModules,
1029
+ );
1030
+ log(`Native-module evidence written: ${nativeModulesFile}`);
1031
+ }
892
1032
  } else {
893
1033
  logStep('1/6', 'Skipping bundle creation (--skip-bundle)');
894
1034
  logStep('2/6', 'Skipping Hermes compilation');
1035
+ if (nativeModulesFile) {
1036
+ const evidence = await readNativeModulesEvidence(
1037
+ nativeModulesFile,
1038
+ config,
1039
+ bundlePath,
1040
+ );
1041
+ nativeModules = evidence.nativeModules;
1042
+ nativeModulesVerified = true;
1043
+ log(`Native-module evidence verified: ${nativeModules.length}${nativeModules.length ? ` (${nativeModules.join(', ')})` : ''}`);
1044
+ } else {
1045
+ logWarning(
1046
+ '--skip-bundle has no --native-modules-file; preserving legacy behaviour without a ' +
1047
+ 'capability fingerprint. Guarded release wrappers should fail before reaching this path.'
1048
+ );
1049
+ }
895
1050
  }
896
1051
 
897
1052
  // Step 3: Collect assets and calculate hashes
@@ -929,13 +1084,12 @@ async function publish(options) {
929
1084
  'Content-Type': 'application/json',
930
1085
  'X-API-Key': config.apiKey,
931
1086
  },
932
- body: JSON.stringify({
933
- runtimeVersion: config.runtimeVersion,
934
- platform: config.platform,
935
- channel: config.channel,
936
- metadata: Object.keys(metadata).length > 0 ? metadata : undefined,
937
- nativeModules: nativeModules.length ? nativeModules : undefined,
938
- }),
1087
+ body: JSON.stringify(createReleaseRequest(
1088
+ config,
1089
+ metadata,
1090
+ nativeModules,
1091
+ nativeModulesVerified,
1092
+ )),
939
1093
  });
940
1094
 
941
1095
  if (!createResponse.ok) {
@@ -963,13 +1117,63 @@ async function publish(options) {
963
1117
  // modules that weren't in the previous good release for this runtime version — native code can't ship
964
1118
  // over the air, so it would crash the installed cohort. Override with --allow-native-change.
965
1119
  let preflight = null;
1120
+ // Any verified capability scan (a direct build or a two-pass evidence handoff) requires a valid
1121
+ // server answer: an unavailable or malformed preflight is not evidence that the OTA is safe, so
1122
+ // it must stop before any asset upload/finalize. Only legacy --skip-bundle without evidence has
1123
+ // no capability set to enforce; --no-native-check remains the one explicit escape hatch.
1124
+ const requiresVerifiedPreflight = nativeModulesVerified && !options['no-native-check'];
1125
+ let pfRes = null;
966
1126
  try {
967
- const pfRes = await fetch(`${config.apiUrl}/api/releases/${release.id}/preflight`, {
1127
+ pfRes = await fetch(`${config.apiUrl}/api/releases/${release.id}/preflight`, {
968
1128
  headers: { 'X-API-Key': config.apiKey },
969
1129
  });
970
- if (pfRes.ok) preflight = await pfRes.json();
971
- } catch {
972
- log('⚠ Preflight check could not run (server unreachable); continuing.');
1130
+ } catch (error) {
1131
+ if (requiresVerifiedPreflight) {
1132
+ throw new Error(
1133
+ `Native ABI preflight could not reach the server; refusing capability-verified publish: ${
1134
+ error instanceof Error ? error.message : String(error)
1135
+ }`,
1136
+ );
1137
+ }
1138
+ logWarning('Preflight check could not run (server unreachable); continuing legacy publish.');
1139
+ }
1140
+ if (pfRes && !pfRes.ok) {
1141
+ if (requiresVerifiedPreflight) {
1142
+ throw new Error(`Native ABI preflight failed with HTTP ${pfRes.status}; refusing capability-verified publish.`);
1143
+ }
1144
+ logWarning(`Preflight check returned HTTP ${pfRes.status}; continuing legacy publish.`);
1145
+ }
1146
+ if (pfRes?.ok) {
1147
+ let decodedPreflight = false;
1148
+ try {
1149
+ preflight = await pfRes.json();
1150
+ decodedPreflight = true;
1151
+ } catch (error) {
1152
+ if (requiresVerifiedPreflight) {
1153
+ throw new Error(
1154
+ `Native ABI preflight returned invalid JSON; refusing capability-verified publish: ${
1155
+ error instanceof Error ? error.message : String(error)
1156
+ }`,
1157
+ );
1158
+ }
1159
+ logWarning('Preflight check returned invalid JSON; continuing legacy publish.');
1160
+ }
1161
+ const validPreflight = decodedPreflight
1162
+ && preflight !== null
1163
+ && typeof preflight === 'object'
1164
+ && !Array.isArray(preflight)
1165
+ && typeof preflight.ok === 'boolean'
1166
+ && Array.isArray(preflight.warnings)
1167
+ && preflight.warnings.every((warning) => typeof warning === 'string')
1168
+ && Array.isArray(preflight.newNativeModules)
1169
+ && preflight.newNativeModules.every((moduleName) => typeof moduleName === 'string');
1170
+ if (decodedPreflight && !validPreflight) {
1171
+ preflight = null;
1172
+ if (requiresVerifiedPreflight) {
1173
+ throw new Error('Native ABI preflight returned an invalid response schema; refusing capability-verified publish.');
1174
+ }
1175
+ logWarning('Preflight check returned an invalid response schema; continuing legacy publish.');
1176
+ }
973
1177
  }
974
1178
  if (preflight) {
975
1179
  for (const w of preflight.warnings || []) log(`⚠ ${w}`);
@@ -1456,8 +1660,15 @@ ${colors.cyan}Options:${colors.reset}
1456
1660
  --channel <channel> Release channel (default: production)
1457
1661
  --bundle-dir <dir> Output directory (default: ./dist)
1458
1662
  --bundle <file> Embedded bundle for register-capabilities (otherwise built automatically)
1663
+ --native-build <n> The build this bundle is for (iOS CFBundleVersion, Android versionCode).
1664
+ Required when the bundle is wrapped with a per-build key: without it the
1665
+ manifest serves the bundle to every build sharing the runtime version,
1666
+ and the ones holding a different key cannot start.
1459
1667
  --entry-file <file> Entry file (default: index.ts)
1460
1668
  --skip-bundle Skip bundle creation (use existing)
1669
+ --native-modules-file <file>
1670
+ Capability evidence handoff for a two-pass/--skip-bundle publish. The
1671
+ build pass writes it; the upload pass validates its context and SHA-256.
1461
1672
  --dry-run Build + validate locally without creating a release on the server
1462
1673
  --allow-native-change Publish even though new native modules were detected (you certify they're
1463
1674
  already in the installed binary). Default is FAIL-CLOSED: a new native module
package/src/config.ts CHANGED
@@ -50,6 +50,12 @@ export type ConfigSignatureStatus = 'not-configured' | 'verified' | 'cached-veri
50
50
  export interface ConfigStorage {
51
51
  getString(key: string): string | null | undefined;
52
52
  set(key: string, value: string): void;
53
+ /**
54
+ * False when `set` only mirrors a write and schedules asynchronous persistence. Durable
55
+ * acknowledgement APIs must fail closed because process death may still lose that write.
56
+ * Omitted means the historical synchronous-storage contract.
57
+ */
58
+ readonly supportsDurableSyncWrites?: boolean;
53
59
  }
54
60
 
55
61
  /**
package/src/init.ts CHANGED
@@ -45,6 +45,7 @@ import {
45
45
  flushEvents,
46
46
  getTrackingInfo,
47
47
  track,
48
+ trackIdempotent,
48
49
  type TrackedEventInput,
49
50
  } from './track';
50
51
 
@@ -140,6 +141,12 @@ export interface PulseClient {
140
141
  configUrl: string;
141
142
  trackUrl: string;
142
143
  track: (event: string, props?: TrackedEventInput['props'], time?: Date) => void;
144
+ trackIdempotent: (
145
+ eventId: string,
146
+ event: string,
147
+ props?: TrackedEventInput['props'],
148
+ time?: Date,
149
+ ) => boolean;
143
150
  flush: () => Promise<number>;
144
151
  setUser: (userId?: string, attributes?: Record<string, string>) => void;
145
152
  clearUser: () => void;
@@ -261,6 +268,7 @@ export function initPulse(opts: InitPulseOptions): PulseClient {
261
268
  configUrl,
262
269
  trackUrl,
263
270
  track,
271
+ trackIdempotent,
264
272
  flush: flushEvents,
265
273
  setUser: (nextUserId, attributes) => {
266
274
  userId = nextUserId?.trim() || undefined;
@@ -328,10 +336,17 @@ export async function initPulseAsync(
328
336
  const loaded = await Promise.all(keys.map(async (key) => [key, await opts.storage.getItem(key)] as const));
329
337
  const memory = new Map(loaded.filter((entry): entry is readonly [string, string] => entry[1] !== null));
330
338
  const storage: ConfigStorage = {
339
+ supportsDurableSyncWrites: false,
331
340
  getString: (key) => memory.get(key),
332
341
  set: (key, value) => {
333
342
  memory.set(key, value);
334
- void opts.storage.setItem(key, value);
343
+ try {
344
+ void Promise.resolve(opts.storage.setItem(key, value)).catch((error) => {
345
+ try { opts.onError?.(error); } catch { /* diagnostics never break persistence */ }
346
+ });
347
+ } catch (error) {
348
+ try { opts.onError?.(error); } catch { /* diagnostics never break persistence */ }
349
+ }
335
350
  },
336
351
  };
337
352
  return initPulse({ ...opts, storage });