FE-??: Extract petrinaut demo-site into @apps/petrinaut-website#8528
FE-??: Extract petrinaut demo-site into @apps/petrinaut-website#8528kube wants to merge 8 commits intocf/h-5655-refactor-selection-logicfrom
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
2 Skipped Deployments
|
PR SummaryMedium Risk Overview Updates the website code to consume the library via Adjusts Written by Cursor Bugbot for commit 6398b7b. This will update automatically on new commits. Configure here. |
🤖 Augment PR SummarySummary: Extracts the Petrinaut demo site into a standalone, private Vite app so it can be developed and deployed independently from the library. Changes:
Technical Notes: The worker-loading changes are aimed at avoiding missing-worker-asset failures when the library is consumed by another app build (e.g., Vite output not copying dependency worker assets). 🤖 Was this summary useful? React with 👍 or 👎 |
| "sideEffects": [ | ||
| "demo-site/**/*.ts" | ||
| ], | ||
| "sideEffects": false, |
There was a problem hiding this comment.
"sideEffects": false looks risky here because Petrinaut emits/ships CSS ("style": "dist/main.css" and CSS imports in the entry), and Webpack consumers can tree-shake CSS side-effect imports away when the package is marked side-effect free, leading to missing styles.
Severity: high
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
|
Warning This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
This stack of pull requests is managed by Graphite. Learn more about stacking. |
| "@local/eslint": "workspace:*", | ||
| "@pandacss/dev": "1.4.3", | ||
| "@sentry/react": "10.22.0", | ||
| "@storybook/react-vite": "10.2.13", |
There was a problem hiding this comment.
Add '@testing-library/react' as a devDependency here since the test files in the library (src/playback/provider.test.tsx and src/simulation/worker/use-simulation-worker.test.ts) still require this dependency for testing React components and hooks.
Spotted by Graphite (based on CI logs)
Is this helpful? React 👍 or 👎 to let us know.
Benchmark results
|
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| resolve_policies_for_actor | user: empty, selectivity: high, policies: 2002 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: medium, policies: 1001 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: high, policies: 3314 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: medium, policies: 1526 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: high, policies: 2078 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: medium, policies: 1033 | Flame Graph |
policy_resolution_medium
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| resolve_policies_for_actor | user: empty, selectivity: high, policies: 102 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: medium, policies: 51 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: high, policies: 269 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: medium, policies: 107 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: high, policies: 133 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: medium, policies: 63 | Flame Graph |
policy_resolution_none
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| resolve_policies_for_actor | user: empty, selectivity: high, policies: 2 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: medium, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: high, policies: 8 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: medium, policies: 3 | Flame Graph |
policy_resolution_small
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| resolve_policies_for_actor | user: empty, selectivity: high, policies: 52 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: medium, policies: 25 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: high, policies: 94 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: medium, policies: 26 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: high, policies: 66 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: medium, policies: 29 | Flame Graph |
read_scaling_complete
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| entity_by_id;one_depth | 1 entities | Flame Graph | |
| entity_by_id;one_depth | 10 entities | Flame Graph | |
| entity_by_id;one_depth | 25 entities | Flame Graph | |
| entity_by_id;one_depth | 5 entities | Flame Graph | |
| entity_by_id;one_depth | 50 entities | Flame Graph | |
| entity_by_id;two_depth | 1 entities | Flame Graph | |
| entity_by_id;two_depth | 10 entities | Flame Graph | |
| entity_by_id;two_depth | 25 entities | Flame Graph | |
| entity_by_id;two_depth | 5 entities | Flame Graph | |
| entity_by_id;two_depth | 50 entities | Flame Graph | |
| entity_by_id;zero_depth | 1 entities | Flame Graph | |
| entity_by_id;zero_depth | 10 entities | Flame Graph | |
| entity_by_id;zero_depth | 25 entities | Flame Graph | |
| entity_by_id;zero_depth | 5 entities | Flame Graph | |
| entity_by_id;zero_depth | 50 entities | Flame Graph |
read_scaling_linkless
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| entity_by_id | 1 entities | Flame Graph | |
| entity_by_id | 10 entities | Flame Graph | |
| entity_by_id | 100 entities | Flame Graph | |
| entity_by_id | 1000 entities | Flame Graph | |
| entity_by_id | 10000 entities | Flame Graph |
representative_read_entity
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/block/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/book/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/building/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/organization/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/page/v/2
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/person/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/playlist/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/song/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/uk-address/v/1
|
Flame Graph |
representative_read_entity_type
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| get_entity_type_by_id | Account ID: bf5a9ef5-dc3b-43cf-a291-6210c0321eba
|
Flame Graph |
representative_read_multiple_entities
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| entity_by_property | traversal_paths=0 | 0 | |
| entity_by_property | traversal_paths=255 | 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true | |
| entity_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false | |
| entity_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true | |
| entity_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true | |
| entity_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:2;properties:2;links:1;link_dests:0;type:true | |
| link_by_source_by_property | traversal_paths=0 | 0 | |
| link_by_source_by_property | traversal_paths=255 | 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true | |
| link_by_source_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false | |
| link_by_source_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true | |
| link_by_source_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true | |
| link_by_source_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:2;properties:2;links:1;link_dests:0;type:true |
scenarios
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| full_test | query-limited | Flame Graph | |
| full_test | query-unlimited | Flame Graph | |
| linked_queries | query-limited | Flame Graph | |
| linked_queries | query-unlimited | Flame Graph |
Move the demo-site from libs/@hashintel/petrinaut into its own private package at apps/petrinaut-website, consuming petrinaut as a workspace dependency instead of importing source directly. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… for website - Bundle Monaco Editor into petrinaut (removed from externals), using selective imports (editor.api.js + typescript.contribution.js) to avoid bundling unnecessary language workers - Add define for process.versions in petrinaut vite config for TypeScript internals - Fix Monaco provider to use new Worker() directly instead of returning a promise - Update Monaco type imports to use editor.api.js path across all sync files - Remove stale demo-site references from petrinaut eslint config - Add eslint.config.js for @apps/petrinaut-website - Fix import/export sorting Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Vite library mode emits worker assets as separate files that consumers can't resolve. Using ?worker&inline inlines the compiled worker code as a string and creates a Blob URL at runtime, making workers self-contained in the library bundle. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
6398b7b to
cbbd3fb
Compare
70dc746 to
11b1e8b
Compare
| const pending = pendingRef.current.get(msg.id); | ||
| if (!pending) { | ||
| return; | ||
| void (async () => { |
There was a problem hiding this comment.
Because the worker is now created asynchronously, callers (e.g. LanguageClientProvider’s mount effect) can hit client.initialize() before workerRef.current is set, so the notification is silently dropped and the language server never initializes.
Severity: high
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
| diagnosticsCallbackRef.current?.(msg.params); | ||
| } | ||
| }; | ||
| workerRef.current = worker; |
There was a problem hiding this comment.
There’s an unmount race here: if the component unmounts before the dynamic import resolves, the cleanup runs with workerRef.current === null, but the async task can still create a worker and assign it after unmount (leaking a live worker).
Severity: medium
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
|
|
||
| /** Dynamically import and instantiate the simulation worker (inlined as blob URL). */ | ||
| async function createSimulationWorker(): Promise<Worker> { | ||
| const SimulationWorker = await import("./simulation.worker.ts?worker&inline"); |
There was a problem hiding this comment.
Switching to import("./simulation.worker.ts?worker&inline") means tests/mocks that stub the global Worker constructor won’t intercept worker creation anymore (the imported module provides the constructor), so use-simulation-worker.test.ts likely needs to mock this import instead.
Severity: medium
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
| }; | ||
|
|
||
| workerRef.current = worker; | ||
| void (async () => { |
There was a problem hiding this comment.
Similar to the LSP hook, the worker is now initialized asynchronously, so actions.initialize() can run before workerRef.current is set; in that case postMessage() no-ops and the returned init Promise can hang indefinitely.
Severity: high
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
|
|
||
| return () => { | ||
| worker.terminate(); | ||
| workerRef.current?.terminate(); |
|
|
||
| window.MonacoEnvironment = { | ||
| getWorker() { | ||
| return new Worker( |
There was a problem hiding this comment.
Worth double-checking that editor.worker.js (loaded via new URL(..., import.meta.url)) is actually available in consuming-app production builds; this looks like it could hit the same “library worker asset not copied → 404” issue that motivated ?worker&inline elsewhere.
Severity: medium
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

🌟 What is the purpose of this PR?
Extract the petrinaut demo-site into its own private package (
@apps/petrinaut-website) so it can be developed, built, and deployed independently of the library.🔍 What does this change?
New package
apps/petrinaut-website/:@apps/petrinaut-website) consuming@hashintel/petrinautas a workspace dependency@typescript/native-previewfor dev/build../../src/to@hashintel/petrinaut@hashintel/petrinaut/dist/main.css)Changes to
@hashintel/petrinaut:demo-site/directory andvite.site.config.tsErrorTrackerContext,ErrorTracker,convertOldFormatToSDCPN,isOldFormat,OldFormatbuild:sitescript, changeddevtovite build --watch@sentry/reactandimmerto the website packagesideEffects: false, removeddemo-sitefrom tsconfig includeseditor.api.js+typescript.contribution.js) to avoid bundling unnecessary language workersdefineforprocess.versionsto fix Monaco's runtime reference to Node globals?worker&inlineimportsWhy
?worker&inline:Vite library mode emits worker files as separate assets, but consuming apps (like
@apps/petrinaut-website) don't copy those assets during their own build — the worker URLs resolve to 404s. This is a known Vite limitation with no clean fix. Using?worker&inlineinlines the compiled worker code as a raw JS string and creates a Blob URL at runtime, making workers fully self-contained in the library bundle. Since Vite 6+, inline workers use raw strings (not base64), so there is no encoding overhead.Pre-Merge Checklist 🚀
🚢 Has this modified a publishable library?
This PR:
📜 Does this require a change to the docs?
The changes in this PR:
🕸️ Does this require a change to the Turbo Graph?
The changes in this PR:
❓ How to test this?
yarn devinapps/petrinaut-website(after building petrinaut)