Skip to content
Open
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
16 changes: 16 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,19 @@ jobs:
VERSION=$(node -p "require('./packages/core/package.json').version")
git tag "v$VERSION"
git push origin "v$VERSION"

- name: Create GitHub release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
VERSION=$(node -p "require('./packages/core/package.json').version")
NOTES=$(node -e "
const fs = require('fs');
const log = fs.readFileSync('packages/core/CHANGELOG.md', 'utf8');
const match = log.match(/## ${VERSION}\n([\s\S]*?)(?=\n## |\$)/);
process.stdout.write(match ? match[1].trim() : 'See CHANGELOG.md for details.');
Comment on lines +93 to +97

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix changelog extraction: ${VERSION} is not interpolated in the regex literal.

The current script treats ${VERSION} as literal text, so the version section match will fail and release notes will always fall back to the default string.

Suggested fix
-          NOTES=$(node -e "
+          NOTES=$(VERSION=\"$VERSION\" node -e "
             const fs = require('fs');
             const log = fs.readFileSync('packages/core/CHANGELOG.md', 'utf8');
-            const match = log.match(/## ${VERSION}\n([\s\S]*?)(?=\n## |\$)/);
+            const version = process.env.VERSION;
+            const escaped = version.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
+            const match = log.match(new RegExp(`## ${escaped}\\n([\\s\\S]*?)(?=\\n## |$)`));
             process.stdout.write(match ? match[1].trim() : 'See CHANGELOG.md for details.');
           ")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
NOTES=$(node -e "
const fs = require('fs');
const log = fs.readFileSync('packages/core/CHANGELOG.md', 'utf8');
const match = log.match(/## ${VERSION}\n([\s\S]*?)(?=\n## |\$)/);
process.stdout.write(match ? match[1].trim() : 'See CHANGELOG.md for details.');
NOTES=$(VERSION=\"$VERSION\" node -e "
const fs = require('fs');
const log = fs.readFileSync('packages/core/CHANGELOG.md', 'utf8');
const version = process.env.VERSION;
const escaped = version.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const match = log.match(new RegExp(`## ${escaped}\\n([\\s\\S]*?)(?=\\n## |$)`));
process.stdout.write(match ? match[1].trim() : 'See CHANGELOG.md for details.');
")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release.yml around lines 93 - 97, The regex literal in the
NOTES node script treats `${VERSION}` as plain text so the changelog section
never matches; update the log.match call inside the NOTES assignment to build
the regex via the RegExp constructor (or a template string passed to RegExp) so
the VERSION variable is interpolated, and ensure the newline and character-class
tokens (like \n and [\s\S]) are properly escaped in the constructed pattern to
preserve the original intent and fallback behavior.

")
gh release create "v$VERSION" \
--title "v$VERSION" \
--notes "$NOTES" \
--verify-tag
Binary file modified .yarn/install-state.gz
Binary file not shown.
16 changes: 9 additions & 7 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,7 @@ To run the sample app on iOS:
yarn sample:run:ios
```

Make sure your code passes TypeScript and ESLint checks.

TODO: Add project-wide `yarn typecheck` and `yarn lint` scripts, then replace this section with:
Make sure your code passes TypeScript and ESLint checks:

```sh
yarn typecheck
Expand All @@ -68,7 +66,9 @@ yarn lint

To fix formatting/lint errors:

TODO: Add and document `yarn lint --fix` once lint setup is available.
```sh
yarn lint --fix
```

Remember to add tests for your change when possible. Run relevant unit tests by:

Expand All @@ -84,9 +84,9 @@ yarn test:storage
The root `package.json` contains scripts for common tasks:

- `yarn install`: install workspace dependencies.
- TODO: Add `yarn typecheck` script for TypeScript checks.
- TODO: Add `yarn lint` script for ESLint checks.
- TODO: Add `yarn lint --fix` support as part of lint setup.
- `yarn typecheck`: run TypeScript checks across all packages.
- `yarn lint`: run ESLint across all packages.
- `yarn lint --fix`: auto-fix lint and formatting errors.
- `yarn packages:build`: build all workspaces in topological order.
- `yarn sample:run:android`: run the sample app on Android.
- `yarn sample:run:ios`: run the sample app on iOS.
Expand Down Expand Up @@ -146,6 +146,7 @@ The CLI will prompt you to select a bump type (`patch`, `minor`, or `major`) and
The changeset description becomes the entry in each package's `CHANGELOG.md` on the next release, linked to your PR and commit SHA. CI will fail if no changeset file is present.

**Bump type guidance:**

- `patch` — bug fixes, non-breaking internal changes
- `minor` — new backwards-compatible features
- `major` — breaking API changes
Expand All @@ -172,6 +173,7 @@ To release, trigger the [Release workflow](../../actions/workflows/release.yml)

**Why `workflow_dispatch` instead of the Changesets bot?**
We deliberately chose manual `workflow_dispatch` instead of the Changesets GitHub bot because:

- This is an early-stage SDK where releases should be deliberate, not automatic
- It avoids a permanently-open "Release PR" that creates pressure to ship before the team is ready
- One explicit button-push makes the release boundary clear
Expand Down
1 change: 0 additions & 1 deletion PingSampleApp/android/settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ dependencyResolutionManagement {
include ':app'
includeBuild('../../node_modules/@react-native/gradle-plugin')

// TODO REVISIT
include(":ping-identity_rn-core")
project(":ping-identity_rn-core").projectDir = file("../../packages/core/android")
include(":ping-identity_rn-oidc")
Expand Down
18 changes: 8 additions & 10 deletions PingSampleApp/ios/PingSampleApp.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -274,14 +274,10 @@
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-PingSampleApp/Pods-PingSampleApp-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
inputPaths = (
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-PingSampleApp/Pods-PingSampleApp-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-PingSampleApp/Pods-PingSampleApp-frameworks.sh\"\n";
Expand Down Expand Up @@ -317,14 +313,10 @@
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-PingSampleApp/Pods-PingSampleApp-resources-${CONFIGURATION}-input-files.xcfilelist",
);
inputPaths = (
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-PingSampleApp/Pods-PingSampleApp-resources-${CONFIGURATION}-output-files.xcfilelist",
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-PingSampleApp/Pods-PingSampleApp-resources.sh\"\n";
Expand Down Expand Up @@ -568,7 +560,10 @@
"-DFOLLY_CFG_NO_COROUTINES=1",
"-DFOLLY_HAVE_CLOCK_GETTIME=1",
);
OTHER_LDFLAGS = "$(inherited) ";
OTHER_LDFLAGS = (
"$(inherited)",
" ",
);
REACT_NATIVE_PATH = "${PODS_ROOT}/../../../node_modules/react-native";
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG";
Expand Down Expand Up @@ -648,7 +643,10 @@
"-DFOLLY_CFG_NO_COROUTINES=1",
"-DFOLLY_HAVE_CLOCK_GETTIME=1",
);
OTHER_LDFLAGS = "$(inherited) ";
OTHER_LDFLAGS = (
"$(inherited)",
" ",
);
REACT_NATIVE_PATH = "${PODS_ROOT}/../../../node_modules/react-native";
SDKROOT = iphoneos;
USE_HERMES = true;
Expand Down
56 changes: 28 additions & 28 deletions PingSampleApp/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2465,7 +2465,7 @@ PODS:
- ReactCommon/turbomodule/core
- SocketRocket
- Yoga
- RNPingBinding (0.1.0):
- RNPingBinding (1.0.0-beta.3):
- boost
- DoubleConversion
- fast_float
Expand Down Expand Up @@ -2496,7 +2496,7 @@ PODS:
- RNPingCore
- SocketRocket
- Yoga
- RNPingBrowser (0.1.0):
- RNPingBrowser (1.0.0-beta.3):
- boost
- DoubleConversion
- fast_float
Expand Down Expand Up @@ -2528,7 +2528,7 @@ PODS:
- RNPingLogger
- SocketRocket
- Yoga
- RNPingCore (0.1.0):
- RNPingCore (1.0.0-beta.3):
- boost
- DoubleConversion
- fast_float
Expand Down Expand Up @@ -2557,7 +2557,7 @@ PODS:
- ReactCommon/turbomodule/core
- SocketRocket
- Yoga
- RNPingDeviceClient (0.1.0):
- RNPingDeviceClient (1.0.0-beta.3):
- boost
- DoubleConversion
- fast_float
Expand Down Expand Up @@ -2588,7 +2588,7 @@ PODS:
- RNPingCore
- SocketRocket
- Yoga
- RNPingDeviceId (0.1.0):
- RNPingDeviceId (1.0.0-beta.3):
- boost
- DoubleConversion
- fast_float
Expand Down Expand Up @@ -2619,7 +2619,7 @@ PODS:
- RNPingCore
- SocketRocket
- Yoga
- RNPingDeviceProfile (0.1.0):
- RNPingDeviceProfile (1.0.0-beta.3):
- boost
- DoubleConversion
- fast_float
Expand Down Expand Up @@ -2650,7 +2650,7 @@ PODS:
- RNPingCore
- SocketRocket
- Yoga
- RNPingExternalIdp (0.1.0):
- RNPingExternalIdp (1.0.0-beta.3):
- boost
- DoubleConversion
- fast_float
Expand Down Expand Up @@ -2681,7 +2681,7 @@ PODS:
- RNPingCore
- SocketRocket
- Yoga
- RNPingFido (0.1.0):
- RNPingFido (1.0.0-beta.3):
- boost
- DoubleConversion
- fast_float
Expand Down Expand Up @@ -2712,7 +2712,7 @@ PODS:
- RNPingCore
- SocketRocket
- Yoga
- RNPingJourney (0.1.0):
- RNPingJourney (1.0.0-beta.3):
- boost
- DoubleConversion
- fast_float
Expand Down Expand Up @@ -2750,7 +2750,7 @@ PODS:
- RNPingCore
- SocketRocket
- Yoga
- RNPingLogger (0.1.0):
- RNPingLogger (1.0.0-beta.3):
- boost
- DoubleConversion
- fast_float
Expand Down Expand Up @@ -2781,7 +2781,7 @@ PODS:
- RNPingCore
- SocketRocket
- Yoga
- RNPingOath (0.1.0):
- RNPingOath (1.0.0-beta.3):
- boost
- DoubleConversion
- fast_float
Expand Down Expand Up @@ -2812,7 +2812,7 @@ PODS:
- RNPingCore
- SocketRocket
- Yoga
- RNPingOidc (0.1.0):
- RNPingOidc (1.0.0-beta.3):
- boost
- DoubleConversion
- fast_float
Expand Down Expand Up @@ -2847,7 +2847,7 @@ PODS:
- RNPingCore
- SocketRocket
- Yoga
- RNPingPush (0.1.0):
- RNPingPush (1.0.0-beta.3):
- boost
- DoubleConversion
- fast_float
Expand Down Expand Up @@ -2880,7 +2880,7 @@ PODS:
- RNPingCore
- SocketRocket
- Yoga
- RNPingStorage (0.1.0):
- RNPingStorage (1.0.0-beta.3):
- boost
- DoubleConversion
- fast_float
Expand Down Expand Up @@ -3589,20 +3589,20 @@ SPEC CHECKSUMS:
ReactCodegen: 1e9f3e8a3f56fa25fbf39ecd37b708a4838d9032
ReactCommon: 96684b90b235d6ae340d126141edd4563b7a446a
RNCAsyncStorage: 767abb068db6ad28b5f59a129fbc9fab18b377e2
RNPingBinding: 64be383c23d1fb0c0899eb650ffb557355111b36
RNPingBrowser: 68c92341be9aed38dd5a11ecee37b96bf96a6332
RNPingCore: f41b28de7c94d2e2af7fae663531d0d0341d2775
RNPingDeviceClient: 6b89f63032ed087e0af22b73312e73a5800cb0ce
RNPingDeviceId: e0d02655613f8e6151496538ce46040f44c414cb
RNPingDeviceProfile: d41184083542e19e85e20ec9938c98f6511931b5
RNPingExternalIdp: 664978f9d40fdcd80af22fb2da1e2b0ec0059371
RNPingFido: 22c9c9f44842fb4e42b8c9c193583314ddd8e61f
RNPingJourney: b85d5fef5498aedda4019108230a39a6135935cb
RNPingLogger: 85893024c3d861ac0e01d35f91860e5bdd3cd904
RNPingOath: f800f54371fa0ee2a849d29fcefdb54eb01eac90
RNPingOidc: d17f951f9ca06652fd97caaaf7aaced99e4ad9e8
RNPingPush: 214ca695aa3779c722fb12ef64cd18fba6fd415b
RNPingStorage: e4f9709832992edd2c49e7885d300aca7cacd68e
RNPingBinding: 10541621edbb8b6885f069ee6316843498d6cc93
RNPingBrowser: 63741144ed5088a03a765a4d7c42be27f18fdd53
RNPingCore: fe4e99005afb728904b634a2b29bd9f7df0ed7a2
RNPingDeviceClient: b62cdc274eff19c09fce49b7d7b7e1166a81a044
RNPingDeviceId: f37f85e0807a5b0e284631c83e28e0dfd4a78712
RNPingDeviceProfile: 90e4220f1ec456f8dfaeb9a4214214100302292c
RNPingExternalIdp: 7954d281fa3ea15681b5b1c6ce6f8813559e9b48
RNPingFido: 350763404cdd05b9fe3dbf73eba926e041d4bf63
RNPingJourney: f3823780322f741fceed6eb6c3c20013d85a44a2
RNPingLogger: 3bb60c3bc67fe1078a4a4535f98129da4845eebf
RNPingOath: f67ef2fedb4ad9727349be6eac5da988196871eb
RNPingOidc: 889badee38ae3a2a592edb723d2047f3eea603c7
RNPingPush: 1ac8fd7f91b9489ec088e502bb8a7b96fabacc80
RNPingStorage: 61024de883275173ac09f95d985f1bb9bef62670
RNScreens: 846d53087db560ed5fbc34feb0643adb5f9602c5
RNSVG: e8fb86f41fccd7b67c4480bb9e179e0ad5785b80
RNVectorIcons: 54df27a2e90ddeb674c7237d76060ec9762d0bc5
Expand Down
26 changes: 17 additions & 9 deletions PingSampleApp/src/hooks/useDevices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { useCallback, useEffect, useRef, useState } from 'react';
import { useJourney } from '@ping-identity/rn-journey';
import {
createDeviceClient,
type DeviceByKind,
type DeviceClient,
type DeviceKind,
type DeviceOf,
Expand All @@ -31,7 +32,7 @@ type Status = 'idle' | 'loading' | 'ready' | 'error';
*/
interface UseDevicesState {
status: Status;
devices: DeviceOf<DeviceKind>[];
devices: DeviceOf<keyof DeviceByKind>[];
/** Human-readable error surfaced from the native bridge, or `null` when healthy. */
error: string | null;
}
Expand All @@ -50,12 +51,15 @@ interface UseDevicesActions {
* Renames a device on the server and re-fetches the list on success.
* Re-fetches on failure too so local state matches the server.
*/
rename: (device: DeviceOf<DeviceKind>, newName: string) => Promise<void>;
rename: (
device: DeviceOf<keyof DeviceByKind>,
newName: string,
) => Promise<void>;
/**
* Deletes a device from the server and re-fetches the list.
* Re-fetches on failure too so local state matches the server.
*/
remove: (device: DeviceOf<DeviceKind>) => Promise<void>;
remove: (device: DeviceOf<keyof DeviceByKind>) => Promise<void>;
}

/**
Expand Down Expand Up @@ -175,11 +179,15 @@ export function useDevices(
setState(s => ({ ...s, status: 'loading', error: null }));
try {
const client = await ensureClient();
const items = await client[deviceType].get();
const items = await (
client[deviceType as keyof typeof client] as {
get: () => Promise<unknown[]>;
}
).get();
if (mountedRef.current) {
setState({
status: 'ready',
devices: items as DeviceOf<DeviceKind>[],
devices: items as DeviceOf<keyof DeviceByKind>[],
error: null,
});
}
Expand Down Expand Up @@ -217,12 +225,12 @@ export function useDevices(
* stays in sync with the server.
*/
const rename = useCallback(
async (device: DeviceOf<DeviceKind>, newName: string) => {
async (device: DeviceOf<keyof DeviceByKind>, newName: string) => {
const client = await ensureClient();
const updated = { ...device, deviceName: newName };
try {
await (
client[deviceType] as {
client[deviceType as keyof typeof client] as {
update: (d: typeof updated) => Promise<unknown>;
}
).update(updated);
Expand All @@ -240,11 +248,11 @@ export function useDevices(
* success and failure paths (the catch is in the consumer).
*/
const remove = useCallback(
async (device: DeviceOf<DeviceKind>) => {
async (device: DeviceOf<keyof DeviceByKind>) => {
const client = await ensureClient();
try {
await (
client[deviceType] as {
client[deviceType as keyof typeof client] as {
delete: (d: typeof device) => Promise<unknown>;
}
).delete(device);
Expand Down
Loading
Loading