Skip to content

Commit 1601090

Browse files
committed
ci: add-fixtures-and-generate-bundles
1 parent 44f9be3 commit 1601090

24 files changed

Lines changed: 745 additions & 0 deletions

.github/workflows/ci.yml

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,3 +198,55 @@ jobs:
198198
199199
---
200200
<sub>🔄 Updated automatically on each push to this PR</sub>
201+
202+
- name: Download feature bundle baseline
203+
uses: dawidd6/action-download-artifact@v3
204+
with:
205+
workflow: publish.yml
206+
branch: main
207+
name: bundle-feature-baseline
208+
path: e2e/bundle-check-app
209+
if_no_artifact_found: warn
210+
continue-on-error: true
211+
212+
- name: Run feature bundle check
213+
id: bundle-features
214+
run: |
215+
pnpm nx nxBundle bundle-check-app --skip-sync --no-agents
216+
{
217+
echo 'report<<BUNDLE_FEATURE_EOF'
218+
cat e2e/bundle-check-app/dist/bundle-feature-report.md
219+
echo 'BUNDLE_FEATURE_EOF'
220+
} >> "$GITHUB_OUTPUT"
221+
222+
- name: Find feature bundle comment
223+
id: find-feature-comment
224+
uses: peter-evans/find-comment@v4
225+
with:
226+
issue-number: ${{ github.event.pull_request.number }}
227+
comment-author: 'github-actions[bot]'
228+
body-includes: <!-- bundle-feature-check -->
229+
230+
- name: Create or update feature bundle comment
231+
uses: peter-evans/create-or-update-comment@v5
232+
with:
233+
comment-id: ${{ steps.find-feature-comment.outputs.comment-id }}
234+
issue-number: ${{ github.event.pull_request.number }}
235+
edit-mode: replace
236+
body: |
237+
<!-- bundle-feature-check -->
238+
## Tree-shaken Feature Bundle Sizes
239+
240+
Minified + gzip level-9 cost of each SDK feature in isolation, as a consumer would receive it.
241+
242+
${{ steps.bundle-features.outputs.report }}
243+
244+
<details>
245+
<summary>How these are measured</summary>
246+
247+
Each fixture imports a single feature and is bundled with Rollup + esbuild + terser (full minification, ESM, tree-shaking on). Numbers reflect what a consumer ships and what their users download, not the raw dist size.
248+
249+
</details>
250+
251+
---
252+
<sub>Updated automatically on each push to this PR</sub>

.github/workflows/publish.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,16 @@ jobs:
9393
path: previous_sizes.json
9494
retention-days: 30
9595

96+
- name: Run feature bundle check
97+
run: pnpm nx nxBundle bundle-check-app --skip-sync
98+
99+
- name: Upload feature bundle baseline
100+
uses: actions/upload-artifact@v5
101+
with:
102+
name: bundle-feature-baseline
103+
path: e2e/bundle-check-app/dist/bundle-feature-baseline.json
104+
retention-days: 30
105+
96106
snapshot:
97107
# Guard against publishing snapshots from the protected release branch.
98108
if: >-
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { davinci } from '@forgerock/davinci-client';
2+
3+
const client = await davinci({
4+
config: {
5+
serverConfig: { wellknown: 'https://example.com/.well-known/openid-configuration' },
6+
clientId: 'test-client',
7+
redirectUri: 'https://example.com/callback',
8+
scope: 'openid profile',
9+
},
10+
});
11+
12+
let node = await client.start();
13+
14+
// Walk the flow until it reaches a terminal node
15+
while (node.status === 'continue') {
16+
for (const collector of node.collectors) {
17+
if (collector.category === 'SingleValueCollector' && collector.type === 'TextCollector') {
18+
client.update(collector)('test-value');
19+
}
20+
if (collector.category === 'SingleValueCollector' && collector.type === 'PasswordCollector') {
21+
client.update(collector)('test-password');
22+
}
23+
}
24+
node = await client.next();
25+
}
26+
27+
if (node.status === 'success') {
28+
console.log('Login successful', node.session);
29+
} else if (node.status === 'error' || node.status === 'failure') {
30+
console.error('Login failed', node.error);
31+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { davinci } from '@forgerock/davinci-client';
2+
3+
const client = await davinci({
4+
config: {
5+
serverConfig: { wellknown: 'https://example.com/.well-known/openid-configuration' },
6+
clientId: 'test-client',
7+
redirectUri: 'https://example.com/callback',
8+
scope: 'openid profile',
9+
},
10+
});
11+
12+
const node = await client.start();
13+
console.log(node);
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { deviceClient } from '@forgerock/device-client';
2+
3+
const client = deviceClient({
4+
serverConfig: {
5+
baseUrl: 'https://example.com/am',
6+
},
7+
realmPath: 'root',
8+
});
9+
10+
// Retrieve OATH (TOTP/HOTP) devices for a user
11+
const oathDevices = await client.oath.get({
12+
userId: 'user@example.com',
13+
});
14+
console.log(oathDevices);
15+
16+
// Retrieve Push notification devices
17+
const pushDevices = await client.push.get({
18+
userId: 'user@example.com',
19+
});
20+
console.log(pushDevices);
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Same usage but imports from the top-level 'effect' barrel instead of 'effect/Option'
2+
// Tests whether the barrel import prevents tree-shaking vs the subpath
3+
import { Option, pipe } from 'effect';
4+
5+
const result = pipe(
6+
Option.fromNullable(Math.random() > 0.5 ? 'hello' : null),
7+
Option.match({
8+
onNone: () => 'none',
9+
onSome: (v) => v.toUpperCase(),
10+
}),
11+
);
12+
13+
console.log(result);
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Imports Option via the subpath: effect/Option
2+
// Tests whether Rollup tree-shakes to only fromNullable + match
3+
import * as Option from 'effect/Option';
4+
import { pipe } from 'effect/Function';
5+
6+
const result = pipe(
7+
Option.fromNullable(Math.random() > 0.5 ? 'hello' : null),
8+
Option.match({
9+
onNone: () => 'none',
10+
onSome: (v) => v.toUpperCase(),
11+
}),
12+
);
13+
14+
console.log(result);
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { journey } from '@forgerock/journey-client';
2+
import { Device } from '@forgerock/journey-client/device';
3+
4+
const client = await journey({
5+
config: { serverConfig: { wellknown: 'https://example.com/.well-known/openid-configuration' } },
6+
});
7+
8+
const step = await client.start();
9+
10+
if (step.type === 'Step') {
11+
const device = new Device();
12+
const profile = await device.getProfile({ collectLocation: false });
13+
console.log(profile);
14+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { journey } from '@forgerock/journey-client';
2+
import { Policy } from '@forgerock/journey-client/policy';
3+
4+
const client = await journey({
5+
config: { serverConfig: { wellknown: 'https://example.com/.well-known/openid-configuration' } },
6+
});
7+
8+
const step = await client.start();
9+
10+
if (step.type === 'Step') {
11+
const errors = Policy.parseErrors(step.callbacks);
12+
console.log(errors);
13+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { journey } from '@forgerock/journey-client';
2+
import { QRCode } from '@forgerock/journey-client/qr-code';
3+
4+
const client = await journey({
5+
config: { serverConfig: { wellknown: 'https://example.com/.well-known/openid-configuration' } },
6+
});
7+
8+
const step = await client.start();
9+
10+
if (step.type === 'Step') {
11+
const qrCode = QRCode.getQRCodeData(step);
12+
console.log(qrCode);
13+
}

0 commit comments

Comments
 (0)