Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# Changelog

## Unreleased
## 0.3.0 (7 Nov 2026)

- `strait init` writes setup for today's SDKs: Android 0.9.0 (JitPack) and iOS 0.10.0 (SwiftPM), was 0.8.4 and 0.9.5; React Native 0.10.2 and Flutter 0.9.7 unchanged. `strait events add` reads the same versions and says the iOS/Android `eventId` needs them.
- `strait events add`: the Flutter snippet shows `eventId` (strait_sdk 0.10.0+ has it); the React Native one says `eventId` needs 0.11.0+.
- `strait init` writes setup for today's SDKs: Android 0.10.0 (JitPack), iOS 0.11.0 (SwiftPM), and Flutter 0.10.1 (was 0.8.4, 0.9.5 and 0.9.7); React Native stays 0.10.2 until 0.11.0 is on npm. `strait events add` reads the same versions and says the iOS/Android `eventId` needs them.
- `strait test`: one pass/fail list that says you're set up right: the engine answers, the secret key is valid (which workspace, test or live), and the workspace's link domain serves apple-app-site-association and assetlinks.json. Exit 1 on any failure, `--json` for CI.
- `strait events add <name>`: prints ready-to-paste event tracking code for React Native, Flutter, iOS, Android or the web (detected from the project files, or `--platform`), using each SDK's real `trackEvent` call.
- `strait events add --platform web` prints `@straitlink/web`'s new `trackEvent` instead of a hand-written `POST /v1/event` (needs the web SDK release that adds it).
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@straitlink/cli",
"version": "0.2.2",
"version": "0.3.0",
"description": "Strait deep links from the terminal: init sets them up in a React Native, Expo, Flutter or Android app, doctor checks your link host, links creates and lists links and saves QR codes.",
"keywords": [
"strait",
Expand Down
10 changes: 6 additions & 4 deletions src/events.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// `strait events add <name>`: prints ready-to-paste tracking code (ADR 0001). Each snippet is the
// SDK's own call, read from its source on 5 Nov 2026:
// React Native 0.10 links.trackEvent(name, { value, currency, eventId }) src/strait.ts
// Flutter 0.9 links.trackEvent(name, value:, currency:, linkId:, clickId:) lib/src/client.dart (no eventId)
// React Native 0.11 links.trackEvent(name, { value, currency, eventId }) src/strait.ts (0.10.2: no eventId)
// Flutter 0.10 links.trackEvent(name, value:, currency:, linkId:, clickId:, eventId:) lib/src/client.dart
// iOS 0.10 strait.trackEvent(_:value:currency:linkId:clickId:eventId:completion:) StraitLinks.swift
// Android 0.8 client.trackEvent(name, value, currency, linkId, clickId, eventId) StraitClient.kt (blocks)
// Web (Unreleased) trackEvent(config, name, { value, currency, eventId }) src/index.ts (sdk-web ADR 0002)
Expand Down Expand Up @@ -68,13 +68,15 @@ const SNIPPETS = {
'react-native': (n) => `import { links } from './links'; // the client strait init wrote; fix the path for this file

// Resolves true when Strait took it; never throws. For revenue add
// { value: 49.99, currency: 'USD', eventId: order.id } (eventId: a retry is counted once).
// { value: 49.99, currency: 'USD', eventId: order.id } (eventId: a retry is counted once;
// eventId needs ${PACKAGES.reactNative} 0.11.0+).
await links.trackEvent('${n}');
`,
flutter: (n) => `import 'links.dart'; // lib/links.dart, the client strait init wrote

// Resolves true when Strait took it; never throws. For revenue add
// value: 49.99, currency: 'USD'
// value: 49.99, currency: 'USD', eventId: order.id (eventId: a retry is counted once;
// needs ${PACKAGES.flutter} 0.10.0+).
await links.trackEvent('${n}');
`,
ios: (n) => `// strait: your StraitLinks instance (strait-sdk-swift README, "Use"). Never throws.
Expand Down
6 changes: 3 additions & 3 deletions src/install.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ export const sourceFor = (src, registry) => (typeof src.source === 'string' ? sr
* `strait events add` reads them too: its iOS/Android eventId needs these SDKs.
*/
export const VERSIONS = {
version: '0.10.0', // Swift (Unity is not written by this CLI)
version: '0.11.0', // Swift (Unity is not written by this CLI)
rnVersion: '0.10.2',
flutterVersion: '0.9.7',
androidVersion: '0.9.0',
flutterVersion: '0.10.1',
androidVersion: '0.10.0',
};

export const PACKAGES = {
Expand Down
2 changes: 1 addition & 1 deletion src/version.mjs
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
// Kept equal to package.json version (test/links.test.mjs checks it). Sent as the API User-Agent.
export const CLI_VERSION = '0.2.2';
export const CLI_VERSION = '0.3.0';
13 changes: 8 additions & 5 deletions test/events.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ test('each platform prints its SDK\'s real event call with the name', async () =
const want = {
'react-native': [/import \{ links \} from '\.\/links'/, /await links\.trackEvent\('purchase'\);/, /value: 49\.99, currency: 'USD', eventId: order\.id/],
flutter: [/import 'links\.dart';/, /await links\.trackEvent\('purchase'\);/, /value: 49\.99, currency: 'USD'/],
ios: [/strait\.trackEvent\("purchase"\) \{ ok in/, /eventId: order\.id/, /StraitSDK 0\.10\.0\+/],
android: [/StraitLinks\.client\.trackEvent\("purchase"\)/, /off the main thread/, /eventId = order\.id/, /strait-sdk-android 0\.9\.0\+/],
ios: [/strait\.trackEvent\("purchase"\) \{ ok in/, /eventId: order\.id/, /StraitSDK 0\.11\.0\+/],
android: [/StraitLinks\.client\.trackEvent\("purchase"\)/, /off the main thread/, /eventId = order\.id/, /strait-sdk-android 0\.10\.0\+/],
web: [/import \{ reportWebOpen, trackEvent \} from '@straitlink\/web'/, /await reportWebOpen\(strait\);/, /await trackEvent\(strait, 'purchase'\);/, /value: 49\.99, currency: 'USD', eventId: order\.id/],
};
for (const [platform, patterns] of Object.entries(want)) {
Expand All @@ -37,9 +37,12 @@ test('each platform prints its SDK\'s real event call with the name', async () =
}
});

test('Flutter has no eventId parameter, so its snippet never shows one', async () => {
const r = await run(['add', 'purchase', '--platform', 'flutter', FIXTURES]);
assert.doesNotMatch(r.out, /eventId/);
test('Flutter 0.10 takes eventId; React Native names the version that has it', async () => {
const f = await run(['add', 'purchase', '--platform', 'flutter', FIXTURES]);
assert.match(f.out, /eventId: order\.id/);
assert.match(f.out, /strait_sdk 0\.10\.0\+/);
const rn = await run(['add', 'purchase', '--platform', 'react-native', FIXTURES]);
assert.match(rn.out, /@straitlink\/react-native 0\.11\.0\+/);
});

test('detects the platform from the project files', async () => {
Expand Down
4 changes: 2 additions & 2 deletions test/init.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ test('Flutter: lib/links.dart, pubspec install from the constant, manifest alrea
assert.match(dart, new RegExp(`publishableKey: '${KEY}'`));
assert.match(dart, /links\.onLink\.listen/);
assert.match(dart, /didChangeAppLifecycleState\(AppLifecycleState state\) => _ctl\.add\(switch \(state\)/, 'flutter analyze: avoid_renaming_method_parameters');
assert.match(dart, /\(strait_sdk 0\.9\.7\)/, 'header names the Flutter SDK version');
assert.match(r.out, /strait_sdk: \^0\.9\.7\n/);
assert.match(dart, /\(strait_sdk 0\.10\.1\)/, 'header names the Flutter SDK version');
assert.match(r.out, /strait_sdk: \^0\.10\.1\n/);
for (const line of installSpecs().flutterPubspec.split('\n')) assert.ok(r.out.includes(` ${line}\n`), line);
assert.match(r.out, /intent filters for acme\.strait\.link and acmeflutter:\/\/ are already there/);
assert.match(r.out, /flutter_deeplinking_enabled" android:value="false"/);
Expand Down
16 changes: 8 additions & 8 deletions test/install.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,22 @@ const root = fileURLToPath(new URL('..', import.meta.url));
const walk = (d) => readdirSync(d).flatMap((n) => (n === 'node_modules' || n === '.git' ? [] : statSync(join(d, n)).isDirectory() ? walk(join(d, n)) : [join(d, n)]));

test('github and registry sources', () => {
// Versions as of 5 Nov 2026 (site.config.json packages = npm / pub.dev / JitPack): RN 0.10.2, Flutter 0.9.7, Android 0.9.0.
// Versions as of 7 Nov 2026 (site.config.json packages = npm / pub.dev / JitPack): RN 0.10.2, Flutter 0.10.1, Android 0.10.0.
const gh = installSpecs({ source: 'github', githubOwner: 'strait-sdks' });
assert.equal(gh.reactNative, 'github:strait-sdks/strait-sdk-react-native#v0.10.2');
assert.equal(gh.android, 'com.github.strait-sdks:strait-sdk-android:v0.9.0');
assert.equal(gh.android, 'com.github.strait-sdks:strait-sdk-android:v0.10.0');
assert.equal(gh.androidRepository, 'https://jitpack.io');
assert.match(gh.flutterPubspec, /url: https:\/\/github\.com\/strait-sdks\/strait-sdk-flutter\n {6}ref: v0\.9\.7/);
assert.match(gh.flutterPubspec, /url: https:\/\/github\.com\/strait-sdks\/strait-sdk-flutter\n {6}ref: v0\.10\.1/);
const today = installSpecs();
assert.equal(today.reactNative, '@straitlink/react-native@0.10.2', 'npm in registry mode (16 Oct)');
assert.equal(today.flutterPubspec, ' strait_sdk: ^0.9.7', 'pub.dev in registry mode (16 Oct)');
assert.equal(today.android, `com.github.${INSTALL.githubOwner}:strait-sdk-android:v0.9.0`, 'Android stays on JitPack');
assert.equal(today.flutterPubspec, ' strait_sdk: ^0.10.1', 'pub.dev in registry mode (16 Oct)');
assert.equal(today.android, `com.github.${INSTALL.githubOwner}:strait-sdk-android:v0.10.0`, 'Android stays on JitPack');
const reg = installSpecs({ ...INSTALL, source: 'registry' });
assert.equal(reg.reactNative, '@straitlink/react-native@0.10.2');
assert.equal(reg.android, 'in.straitlink:strait-sdk-android:0.9.0');
assert.equal(reg.flutterPubspec, ' strait_sdk: ^0.9.7');
assert.equal(reg.android, 'in.straitlink:strait-sdk-android:0.10.0');
assert.equal(reg.flutterPubspec, ' strait_sdk: ^0.10.1');
assert.equal(reg.androidRepository, null);
assert.equal(VERSIONS.version, '0.10.0', 'Swift tag v0.10.0 (SwiftPM)');
assert.equal(VERSIONS.version, '0.11.0', 'Swift tag v0.11.0 (SwiftPM)');
});

test('the owner is spelled out only in src/install.mjs', () => {
Expand Down
Loading