| A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | Repository | PR No | Pr Description | Suggestion | Comment By | Date | Small Diff | results | is_false_positive | final_result | PR URL | ||||||||||||||
4 | https://github.com/whiterose911911911/bruno-auto-clones | 11 | # Description Fixes: https://github.com/usebruno/bruno/issues/3688 ### Contribution Checklist: - [x] **The pull request only addresses one issue or adds one feature.** - [x] **The pull request does not introduce any breaking changes** - [ ] **I have added screenshots or gifs to help explain the change if applicable.** - [x] **I have read the [contribution guidelines](https://github.com/usebruno/bruno/blob/main/contributing.md).** - [x] **Create an issue and link to the pull request.** <!-- Note: Keeping the PR small and focused helps make it easier to review and merge. If you have multiple changes you want to make, please consider submitting them as separate pull requests. ### Publishing to New Package Managers Please see [here](../publishing.md) for more information. --> | Duplicate WSSE header construction logic found for both collection and request auth modes; consider extracting this into a common utility function to reduce code repetition. ```js function buildWsseHeader(username, password) { const ts = new Date().toISOString(); const nonce = crypto.randomBytes(16).toString('hex'); const hash = crypto.createHash('sha1'); hash.update(nonce + ts + password); const digest = Buffer.from(hash.digest('hex').toString('utf8')).toString('base64'); return `UsernameToken Username="${username}", PasswordDigest="${digest}", Nonce="${nonce}", Created="${ts}"`; } ``` | pantomaxbot[bot] | 2025-03-24T12:27:15Z | @@ -65,6 +65,50 @@ const prepareRequest = (item = {}, collection = {}) => { } } } + + if (collectionAuth.mode === 'awsv4') { + axiosRequest.awsv4config = { + accessKeyId: get(collectionAuth, 'awsv4.accessKeyId'), + secretAccessKey: get(collectionAuth, 'awsv4.secretAccessKey'), + sessionToken: get(collectionAuth, 'awsv4.sessionToken'), + service: get(collectionAuth, 'awsv4.service'), + region: get(collectionAuth, 'awsv4.region'), + profileName: get(collectionAuth, 'awsv4.profileName') + }; + } + + if (collectionAuth.mode === 'ntlm') { + axiosRequest.ntlmConfig = { + username: get(collectionAuth, 'ntlm.username'), + password: get(collectionAuth, 'ntlm.password'), + domain: get(collectionAuth, 'ntlm.domain') + }; + } + + if (collectionAuth.mode === 'wsse') { + const username = get(collectionAuth, 'wsse.username', ''); + const password = get(collectionAuth, 'wsse.password', ''); + + const ts = new Date().toISOString(); + const nonce = crypto.randomBytes(16).toString('hex'); + + // Create the password digest using SHA-1 as required for WSSE + const hash = crypto.createHash('sha1'); + hash.update(nonce + ts + password); + const digest = Buffer.from(hash.digest('hex').toString('utf8')).toString('base64'); + + // Construct the WSSE header + axiosRequest.headers[ + 'X-WSSE' + ] = `UsernameToken Username="${username}", PasswordDigest="${digest}", Nonce="${nonce}", Created="${ts}"`; + } | REFACTORING | FALSE | REFACTORING | https://github.com/whiterose911911911/bruno-auto-clones/pull/11 | ||||||||||||||
13 | https://github.com/whiterose911911911/slop-auto-clones | 1 | Hi there! I was replacing OptionParser on a project with Slop, but noticed it would use a predefined default value instead of raising an error if a provided value could not be applied to a given option. (Fixes #262) This PR adds a new option, `validate_types` to both `Option` and `Options`, allowing types to be checked while maintaining compatibility with Slop's current behaviour, so no breaking changes are introduced. | Cache the result of valid?(value) in a local variable to avoid computing it twice and potential side effects ```ruby valid_result = valid?(value) if validate_type? && !valid_result && !suppress_errors? raise Slop::InvalidOptionValue.new("invalid value for #{flag}", flags) end @value = valid_result && call(value) ``` | pantomaxbot[bot] | 2025-03-24T12:30:47Z | @@ -56,7 +56,11 @@ def ensure_call(value) raise Slop::MissingArgument.new("missing argument for #{flag}", flags) end else - @value = call(value) + if validate_type? && !valid?(value) && !suppress_errors? + raise Slop::InvalidOptionValue.new("invalid value for #{flag}", flags) + end + + @value = valid?(value) && call(value) | REFACTORING | FALSE | REFACTORING | https://github.com/whiterose911911911/slop-auto-clones/pull/1 | ||||||||||||||
14 | https://github.com/whiterose911911911/slop-auto-clones | 1 | Hi there! I was replacing OptionParser on a project with Slop, but noticed it would use a predefined default value instead of raising an error if a provided value could not be applied to a given option. (Fixes #262) This PR adds a new option, `validate_types` to both `Option` and `Options`, allowing types to be checked while maintaining compatibility with Slop's current behaviour, so no breaking changes are introduced. | Return an explicit boolean (e.g. using !!) in IntegerOption#valid? to make the intent clearer ```ruby def valid?(value) !!(value =~ INT_STRING_REGEXP) end ``` | pantomaxbot[bot] | 2025-03-24T12:30:49Z | @@ -52,8 +59,14 @@ def expects_argument? # Cast the option argument to an Integer. class IntegerOption < Option + INT_STRING_REGEXP = /\A[+-]?\d+\z/.freeze + + def valid?(value) + value =~ INT_STRING_REGEXP + end | REFACTORING | FALSE | REFACTORING | https://github.com/whiterose911911911/slop-auto-clones/pull/1 | ||||||||||||||
15 | https://github.com/whiterose911911911/slop-auto-clones | 1 | Hi there! I was replacing OptionParser on a project with Slop, but noticed it would use a predefined default value instead of raising an error if a provided value could not be applied to a given option. (Fixes #262) This PR adds a new option, `validate_types` to both `Option` and `Options`, allowing types to be checked while maintaining compatibility with Slop's current behaviour, so no breaking changes are introduced. | Return an explicit boolean (e.g. using !!) in FloatOption#valid? to ensure consistent boolean logic ```ruby def valid?(value) !!(value =~ FLOAT_STRING_REGEXP) end ``` | pantomaxbot[bot] | 2025-03-24T12:30:51Z | @@ -62,8 +75,12 @@ def call(value) class FloatOption < Option FLOAT_STRING_REGEXP = /\A[+-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+-]?\d+)?\z/.freeze + def valid?(value) + value =~ FLOAT_STRING_REGEXP + end + | REFACTORING | FALSE | REFACTORING | https://github.com/whiterose911911911/slop-auto-clones/pull/1 | ||||||||||||||
29 | https://github.com/whiterose911911911/click-auto-clones | 1 | https://github.com/pallets/click/issues/2819#issue-2740233946 fixes #2819 <!-- Ensure each step in CONTRIBUTING.rst is complete, especially the following: - Add tests that demonstrate the correct behavior of the change. Tests should fail without the change. - Add or update relevant docs, in the docs folder and in code. - Add an entry in CHANGES.rst summarizing the change and linking to the issue. - Add `.. versionchanged::` entries in any relevant code docs. --> | Consider using more robust error message validation (e.g. regex matching or error codes) instead of relying on an exact message ("Invalid value for '--help'") to avoid future brittleness ```py assert re.search(r"Invalid value for '--help'", result.output) ``` | pantomaxbot[bot] | 2025-03-24T12:32:49Z | @@ -413,3 +414,49 @@ def cli(): assert rv.exit_code == 1 assert isinstance(rv.exception.__cause__, exc) assert rv.exception.__cause__.args == ("catch me!",) + + +def test_argument_named_help(): + @click.command() + @click.argument("help") + def my_command(help): + click.echo(help) + + runner = CliRunner() + result = runner.invoke(my_command, ["test"]) + + assert result.exit_code != 0 + assert "Invalid value for '--help'" in result.output | REFACTORING | FALSE | REFACTORING | https://github.com/whiterose911911911/click-auto-clones/pull/1 | ||||||||||||||
30 | https://github.com/whiterose911911911/click-auto-clones | 1 | https://github.com/pallets/click/issues/2819#issue-2740233946 fixes #2819 <!-- Ensure each step in CONTRIBUTING.rst is complete, especially the following: - Add tests that demonstrate the correct behavior of the change. Tests should fail without the change. - Add or update relevant docs, in the docs folder and in code. - Add an entry in CHANGES.rst summarizing the change and linking to the issue. - Add `.. versionchanged::` entries in any relevant code docs. --> | Use flexible matching for the error message ("Error: Option '--help' requires an argument.") to accommodate any minor changes in future versions of Click ```py assert re.search(r"Error: Option '--help' requires an argument\.", result_with_help.output) ``` | pantomaxbot[bot] | 2025-03-24T12:32:51Z | @@ -413,3 +414,49 @@ def cli(): assert rv.exit_code == 1 assert isinstance(rv.exception.__cause__, exc) assert rv.exception.__cause__.args == ("catch me!",) + + +def test_argument_named_help(): + @click.command() + @click.argument("help") + def my_command(help): + click.echo(help) + + runner = CliRunner() + result = runner.invoke(my_command, ["test"]) + + assert result.exit_code != 0 + assert "Invalid value for '--help'" in result.output + + +def test_option_named_help(): + @click.command() + @click.option("--help", default="this_2") + def my_command(help): + click.echo(help) + + runner = CliRunner() + + # Invoke without --help, should succeed + result_without_help = runner.invoke(my_command) + assert result_without_help.exit_code == 0 + assert result_without_help.output.strip() == "this_2" + + # Invoke with --help, should fail + result_with_help = runner.invoke(my_command, ["--help"]) + assert result_with_help.exit_code != 0 + assert "Error: Option '--help' requires an argument." in result_with_help.output + | REFACTORING | FALSE | REFACTORING | https://github.com/whiterose911911911/click-auto-clones/pull/1 | ||||||||||||||
33 | https://github.com/whiterose911911911/ai-chatbot-auto-clones | 1 | - Wrapped JSON parsing in a try/catch to handle invalid JSON input properly. - Improved error handling for database operations (chat retrieval, saving messages). - Ensured consistent timestamp usage by generating a single `now` timestamp for all related messages. - Standardized error responses to return structured JSON instead of plain text. - Added inline comments to improve code readability. - Improved tool initialization consistency by ensuring `createDocument`, `updateDocument`, and `requestSuggestions` are instantiated similarly. This improves maintainability, error handling, and response clarity. | Replace the use of "any" for the parsed request body with a defined TypeScript interface to improve type safety. ```ts interface ChatRequestBody { id: string; messages: Message[]; selectedChatModel: string; } export async function POST(request: Request) { let body: ChatRequestBody; try { body = await request.json() as ChatRequestBody; } catch (err) { return new Response(JSON.stringify({ error: 'Invalid JSON' }), { status: 400, headers: { 'Content-Type': 'application/json' }, }); } const { id, messages, selectedChatModel } = body; // Rest of the logic... } ``` | pantomaxbot[bot] | 2025-03-24T12:33:25Z | @@ -26,38 +26,60 @@ import { updateDocument } from '@/lib/ai/tools/update-document'; import { requestSuggestions } from '@/lib/ai/tools/request-suggestions'; import { getWeather } from '@/lib/ai/tools/get-weather'; -export const maxDuration = 60; +// Remove unused exports if not needed +// export const maxDuration = 60; export async function POST(request: Request) { - const { - id, - messages, - selectedChatModel, - }: { id: string; messages: Array<Message>; selectedChatModel: string } = - await request.json(); + let body: any; + try { + body = await request.json(); + } catch (err) { + return new Response(JSON.stringify({ error: 'Invalid JSON' }), { + status: 400, + headers: { 'Content-Type': 'application/json' }, + }); + } | REFACTORING | FALSE | REFACTORING | https://github.com/whiterose911911911/ai-chatbot-auto-clones/pull/1 | ||||||||||||||
34 | https://github.com/whiterose911911911/ai-chatbot-auto-clones | 1 | - Wrapped JSON parsing in a try/catch to handle invalid JSON input properly. - Improved error handling for database operations (chat retrieval, saving messages). - Ensured consistent timestamp usage by generating a single `now` timestamp for all related messages. - Standardized error responses to return structured JSON instead of plain text. - Added inline comments to improve code readability. - Improved tool initialization consistency by ensuring `createDocument`, `updateDocument`, and `requestSuggestions` are instantiated similarly. This improves maintainability, error handling, and response clarity. | Consider extracting the repeated unauthorized response creation into a helper function to avoid duplication and ensure consistency. ```ts function unauthorizedResponse() { return new Response(JSON.stringify({ error: 'Unauthorized' }), { status: 401, headers: { 'Content-Type': 'application/json' }, }); } // Example usage: if (!session || !session.user || !session.user.id) { return unauthorizedResponse(); } ``` | pantomaxbot[bot] | 2025-03-24T12:33:27Z | @@ -26,38 +26,60 @@ import { updateDocument } from '@/lib/ai/tools/update-document'; import { requestSuggestions } from '@/lib/ai/tools/request-suggestions'; import { getWeather } from '@/lib/ai/tools/get-weather'; -export const maxDuration = 60; +// Remove unused exports if not needed +// export const maxDuration = 60; export async function POST(request: Request) { - const { - id, - messages, - selectedChatModel, - }: { id: string; messages: Array<Message>; selectedChatModel: string } = - await request.json(); + let body: any; + try { + body = await request.json(); + } catch (err) { + return new Response(JSON.stringify({ error: 'Invalid JSON' }), { + status: 400, + headers: { 'Content-Type': 'application/json' }, + }); + } + + const { id, messages, selectedChatModel }: { id: string; messages: Array<Message>; selectedChatModel: string } = body; const session = await auth(); if (!session || !session.user || !session.user.id) { - return new Response('Unauthorized', { status: 401 }); + return new Response(JSON.stringify({ error: 'Unauthorized' }), { + status: 401, + headers: { 'Content-Type': 'application/json' }, + }); | REFACTORING | FALSE | REFACTORING | https://github.com/whiterose911911911/ai-chatbot-auto-clones/pull/1 | ||||||||||||||
36 | https://github.com/whiterose911911911/ai-chatbot-auto-clones | 11 | - Added `userScrolledRef` to track manual scrolling. - Introduced `autoScrollInProgress` to distinguish between user and auto scrolls. - Used `scrollend` event (or fallback `setTimeout`) to reset auto-scroll state. - Auto-scroll now pauses during user interaction and resumes when scrolled to bottom. | consider adding cleanup logic for the "scrollend" event listener in case it never fires (to avoid potential memory leaks) ```ts // Define handleScrollEnd outside the observer callback so it can be cleaned up. const handleScrollEnd = () => { autoScrollInProgress.current = false; container.removeEventListener("scrollend", handleScrollEnd); }; if ("onscrollend" in window) { container.addEventListener("scrollend", handleScrollEnd); } else { setTimeout(() => { autoScrollInProgress.current = false; }, 1000); } // In the cleanup function, remove the scrollend listener if it was added: return () => { observer.disconnect(); container.removeEventListener("scroll", handleScroll); if ("onscrollend" in window) { container.removeEventListener("scrollend", handleScrollEnd); } }; ``` | pantomaxbot[bot] | 2025-03-24T12:36:57Z | @@ -1,29 +1,60 @@ -import { useEffect, useRef, type RefObject } from 'react'; +import { useEffect, useRef, type RefObject } from "react"; export function useScrollToBottom<T extends HTMLElement>(): [ RefObject<T>, RefObject<T>, ] { const containerRef = useRef<T>(null); const endRef = useRef<T>(null); + const userScrolledRef = useRef(false); + const autoScrollInProgress = useRef(false); useEffect(() => { const container = containerRef.current; const end = endRef.current; if (container && end) { const observer = new MutationObserver(() => { - end.scrollIntoView({ behavior: 'instant', block: 'end' }); + if (!userScrolledRef.current) { + autoScrollInProgress.current = true; + end.scrollIntoView({ behavior: "smooth", block: "end" }); + + const handleScrollEnd = () => { + autoScrollInProgress.current = false; + container.removeEventListener("scrollend", handleScrollEnd); + }; + + if ("onscrollend" in window) { + container.addEventListener("scrollend", handleScrollEnd); + } else { + setTimeout(() => { + autoScrollInProgress.current = false; + }, 1000); + } | REFACTORING | FALSE | REFACTORING | https://github.com/whiterose911911911/ai-chatbot-auto-clones/pull/11 | ||||||||||||||
38 | https://github.com/whiterose911911911/ai-chatbot-auto-clones | 11 | - Added `userScrolledRef` to track manual scrolling. - Introduced `autoScrollInProgress` to distinguish between user and auto scrolls. - Used `scrollend` event (or fallback `setTimeout`) to reset auto-scroll state. - Auto-scroll now pauses during user interaction and resumes when scrolled to bottom. | the bottom detection logic uses a fixed 1px threshold; verify this meets all design cases or consider a more robust calculation ```ts // Consider parameterizing the threshold for bottom detection to handle edge cases const threshold = 3; // Adjust threshold value based on design needs const isAtBottom = scrollHeight - (scrollTop + clientHeight) < threshold; ``` | pantomaxbot[bot] | 2025-03-24T12:37:01Z | @@ -1,29 +1,60 @@ -import { useEffect, useRef, type RefObject } from 'react'; +import { useEffect, useRef, type RefObject } from "react"; export function useScrollToBottom<T extends HTMLElement>(): [ RefObject<T>, RefObject<T>, ] { const containerRef = useRef<T>(null); const endRef = useRef<T>(null); + const userScrolledRef = useRef(false); + const autoScrollInProgress = useRef(false); useEffect(() => { const container = containerRef.current; const end = endRef.current; if (container && end) { const observer = new MutationObserver(() => { - end.scrollIntoView({ behavior: 'instant', block: 'end' }); + if (!userScrolledRef.current) { + autoScrollInProgress.current = true; + end.scrollIntoView({ behavior: "smooth", block: "end" }); + + const handleScrollEnd = () => { + autoScrollInProgress.current = false; + container.removeEventListener("scrollend", handleScrollEnd); + }; + + if ("onscrollend" in window) { + container.addEventListener("scrollend", handleScrollEnd); + } else { + setTimeout(() => { + autoScrollInProgress.current = false; + }, 1000); + } + } }); + const handleScroll = () => { + if (autoScrollInProgress.current) return; + + const { scrollTop, scrollHeight, clientHeight } = container; + const isAtBottom = scrollHeight - (scrollTop + clientHeight) < 1; | REFACTORING | FALSE | REFACTORING | https://github.com/whiterose911911911/ai-chatbot-auto-clones/pull/11 | ||||||||||||||
44 | https://github.com/whiterose911911911/ai-auto-clones | 6 | Consider using a unique value from 'part' as the key (if available) instead of the index 'i' to ensure stability when the list reorders. ```jsx {message.parts.map((part, i) => { // Use a unique value from part if available, fallback to index if needed const key = part.id || `${message.id}-${i}`; switch (part.type) { case 'text': return <div key={key}>{part.text}</div>; } })} ``` | pantomaxbot[bot] | 2025-03-24T12:39:45Z | @@ -138,7 +138,7 @@ export default function Chat() { {messages.map(message => ( <div key={message.id} className="whitespace-pre-wrap"> {message.role === 'user' ? 'User: ' : 'AI: '} - {message.parts.map(part => { + {message.parts.map((part, i) => { | REFACTORING | FALSE | REFACTORING | https://github.com/whiterose911911911/ai-auto-clones/pull/6 | |||||||||||||||
45 | https://github.com/whiterose911911911/ai-auto-clones | 6 | Add a default case in the switch statement to gracefully handle unexpected 'part' types. ```jsx {message.parts.map((part, i) => { const key = part.id || `${message.id}-${i}`; switch (part.type) { case 'text': return <div key={key}>{part.text}</div>; default: // Handle unexpected part types gracefully return <div key={key}>Unsupported part type</div>; } })} ``` | pantomaxbot[bot] | 2025-03-24T12:39:47Z | @@ -138,7 +138,7 @@ export default function Chat() { {messages.map(message => ( <div key={message.id} className="whitespace-pre-wrap"> {message.role === 'user' ? 'User: ' : 'AI: '} - {message.parts.map(part => { + {message.parts.map((part, i) => { switch (part.type) { | REFACTORING | FALSE | REFACTORING | https://github.com/whiterose911911911/ai-auto-clones/pull/6 | |||||||||||||||
49 | https://github.com/whiterose911911911/test-pr-review-auto-clones | 1 | Requirement: - User should be able to expire the payment link using the library - User should pass a reason to expire the link | Update expire_payment_link signature to include a 'reason' parameter so that users can supply a reason for expiring the link as per business requirements ```py @Decorators.auth_handler def expire_payment_link(self, platform_bill_id: str, reason: str): """Expire payment link with a reason.""" base_url = self._getBaseUrl() headers = { "X-Setu-Product-Instance-ID": self.product_instance_id, "Content-Type": "application/json", } payload = {"reason": reason} res = self.session.post( f"{base_url}/utilities/bills/{platform_bill_id}/expire", headers=headers, json=payload, ) return res ``` | pantomaxbot[bot] | 2025-03-24T12:43:24Z | @@ -238,6 +239,23 @@ def trigger_mock_settlement(self, utrs: List[str]): ) return + def _getBaseUrl(): + return PRODUCTION_BASE + + @Decorators.auth_handler + def expire_payment_link(self, platform_bill_id: str): | REFACTORING | FALSE | REFACTORING | https://github.com/whiterose911911911/test-pr-review-auto-clones/pull/1 | ||||||||||||||
79 | https://github.com/whiterose911911911/storybook-auto-clones | 1 | <!-- If your PR is related to an issue, provide the number(s) above; if it resolves multiple issues, be sure to break them up (e.g. "closes #1000, closes #1001"). --> <!-- Thank you for contributing to Storybook! Please submit all PRs to the `next` branch unless they are specific to the current release. Storybook maintainers cherry-pick bug and documentation fixes into the `main` branch as part of the release process, so you shouldn't need to worry about this. For additional guidance: https://storybook.js.org/docs/contribute --> ## What I did This PR adds two methods to the UniversalStore, in anticipation of their needs later: 1. `untilEvent` - wait for an event to fire once, or optionally also another event that rejects the promise instead 2. `toChannelEvent` - converts a universal store event to a raw channel event that can be sent directly on the channel when necessary. Also added usage examples to all methods in JSDocs <!-- Briefly describe what your PR does --> ## Checklist for Contributors ### Testing <!-- Please check (put an "x" inside the "[ ]") the applicable items below to communicate how to test your changes --> #### The changes in this PR are covered in the following automated tests: - [ ] stories - [x] unit tests - [ ] integration tests - [ ] end-to-end tests #### Manual testing _This section is mandatory for all contributions. If you believe no manual test is necessary, please state so explicitly. Thanks!_ <!-- Please include the steps to test your changes here. For example: 1. Run a sandbox for template, e.g. `yarn task --task sandbox --start-from auto --template react-vite/default-ts` 2. Open Storybook in your browser 3. Access X story --> ### Documentation <!-- Please check (put an "x" inside the "[ ]") the applicable items below to indicate which documentation has been updated. --> - [ ] Add or update documentation reflecting your changes - [ ] If you are deprecating/removing a feature, make sure to update [MIGRATION.MD](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md) ## Checklist for Maintainers - [ ] When this PR is ready for testing, make sure to add `ci:normal`, `ci:merged` or `ci:daily` GH label to it to run a specific set of sandboxes. The particular set of sandboxes can be found in `code/lib/cli-storybook/src/sandbox-templates.ts` - [ ] Make sure this PR contains **one** of the labels below: <details> <summary>Available labels</summary> - `bug`: Internal changes that fixes incorrect behavior. - `maintenance`: User-facing maintenance tasks. - `dependencies`: Upgrading (sometimes downgrading) dependencies. - `build`: Internal-facing build tooling & test updates. Will not show up in release changelog. - `cleanup`: Minor cleanup style change. Will not show up in release changelog. - `documentation`: Documentation **only** changes. Will not show up in release changelog. - `feature request`: Introducing a new feature. - `BREAKING CHANGE`: Changes that break compatibility in some way with current major version. - `other`: Changes that don't fit in the above categories. </details> ### 🦋 Canary release <!-- CANARY_RELEASE_SECTION --> This PR does not have a canary release associated. You can request a canary release of this pull request by mentioning the `@storybookjs/core` team here. _core team members can create a canary release [here](https://github.com/storybookjs/storybook/actions/workflows/canary-release-pr.yml) or locally with `gh workflow run --repo storybookjs/storybook canary-release-pr.yml --field pr=<PR_NUMBER>`_ <!-- CANARY_RELEASE_SECTION --> <!-- BENCHMARK_SECTION --> | name | before | after | diff | z | % | | ---- | ------ | ----- | ---- | - | - | | createSize | 0 B | 0 B | 0 B | - | - | | generateSize | 79.7 MB | 79.7 MB | 106 B | 0.44 | 0% | | initSize | 79.7 MB | 79.7 MB | 106 B | 0.44 | 0% | | diffSize | 97 B | 97 B | 0 B | - | 0% | | buildSize | 7.31 MB | 7.31 MB | 5.34 kB | 1.09 | 0.1% | | buildSbAddonsSize | 1.9 MB | 1.9 MB | 1.31 kB | 0.67 | 0.1% | | buildSbCommonSize | 195 kB | 195 kB | 0 B | - | 0% | | buildSbManagerSize | 1.89 MB | 1.89 MB | 3.6 kB | 0.5 | 0.2% | | buildSbPreviewSize | 0 B | 0 B | 0 B | - | - | | buildStaticSize | 0 B | 0 B | 0 B | - | - | | buildPrebuildSize | 3.98 MB | 3.99 MB | 4.91 kB | **2.02** | 0.1% | | buildPreviewSize | 3.33 MB | 3.33 MB | 437 B | 0.4 | 0% | | testBuildSize | 0 B | 0 B | 0 B | - | - | | testBuildSbAddonsSize | 0 B | 0 B | 0 B | - | - | | testBuildSbCommonSize | 0 B | 0 B | 0 B | - | - | | testBuildSbManagerSize | 0 B | 0 B | 0 B | - | - | | testBuildSbPreviewSize | 0 B | 0 B | 0 B | - | - | | testBuildStaticSize | 0 B | 0 B | 0 B | - | - | | testBuildPrebuildSize | 0 B | 0 B | 0 B | - | - | | testBuildPreviewSize | 0 B | 0 B | 0 B | - | - | | name | before | after | diff | z | % | | ---- | ------ | ----- | ---- | - | - | | createTime | 19.8s | 8s | -11s -767ms | -0.97 | -146% | | generateTime | 18.7s | 21.7s | 3s | 0.75 | 13.9% | | initTime | 4.3s | 4.8s | 517ms | 0.18 | 10.7% | | buildTime | 8.2s | 9s | 814ms | -0.57 | 9% | | testBuildTime | 0ms | 0ms | 0ms | - | - | | devPreviewResponsive | 5.3s | 6.3s | 997ms | **1.72** | 🔺15.6% | | devManagerResponsive | 5.1s | 5.9s | 785ms | **1.54** | 🔺13.1% | | devManagerHeaderVisible | 781ms | 914ms | 133ms | 0.6 | 14.6% | | devManagerIndexVisible | 791ms | 994ms | 203ms | 0.87 | 20.4% | | devStoryVisibleUncached | 1.7s | 2.6s | 897ms | **2.51** | 🔺34.1% | | devStoryVisible | 810ms | 993ms | 183ms | 0.58 | 18.4% | | devAutodocsVisible | 842ms | 884ms | 42ms | 0.82 | 4.8% | | devMDXVisible | 703ms | 888ms | 185ms | 0.94 | 20.8% | | buildManagerHeaderVisible | 665ms | 803ms | 138ms | 0.55 | 17.2% | | buildManagerIndexVisible | 727ms | 900ms | 173ms | 0.95 | 19.2% | | buildStoryVisible | 649ms | 788ms | 139ms | 0.75 | 17.6% | | buildAutodocsVisible | 581ms | 704ms | 123ms | 0.64 | 17.5% | | buildMDXVisible | 547ms | 747ms | 200ms | **1.53** | 🔺26.8% | <!-- BENCHMARK_SECTION --> | Avoid using "as any" in the resolution and rejection of the untilEvent promise; instead, properly type the returned object to maintain type safety. ```ts resolve({ event, eventInfo } as { event: TEvent; eventInfo: EventInfo }); reject({ event, eventInfo } as { event: TEvent; eventInfo: EventInfo }); ``` | pantomaxbot[bot] | 2025-03-24T12:50:49Z | @@ -467,9 +528,52 @@ export class UniversalStore< }; }; + /** + * Wait for a specific event to be sent _once_. + * + * This is useful if you only want to wait for an event to be sent once, and not continuously. + * Optionally supply a second event, that will reject the promise if that is sent first. + * + * @example + * + * ```typescript + * try { + * const { event, eventInfo } = await store.untilEvent('TASK_COMPLETED', 'TASK_FAILED'); + * console.log('Task completed', event, eventInfo); + * } catch ({ event, eventInfo }) { + * console.error('Task failed', event, eventInfo); + * } + * ``` + */ + public untilEvent<TEvent extends Event<State, CustomEvent>>( + resolveEventType: TEvent['type'], + rejectEventType?: TEvent['type'] + ): Promise<{ event: TEvent; eventInfo: EventInfo }> { + return new Promise<{ event: TEvent; eventInfo: EventInfo }>((resolve, reject) => { + const unsubscribe = this.subscribe((event, eventInfo) => { + if (event.type === resolveEventType) { + unsubscribe(); + resolve({ event, eventInfo } as any); + } else if (rejectEventType && event.type === rejectEventType) { + unsubscribe(); + reject({ event, eventInfo } as any); | REFACTORING | FALSE | REFACTORING | https://github.com/whiterose911911911/storybook-auto-clones/pull/1 | ||||||||||||||
82 | |||||||||||||||||||||||||
83 | |||||||||||||||||||||||||
84 | |||||||||||||||||||||||||
85 | |||||||||||||||||||||||||
86 | |||||||||||||||||||||||||
87 | |||||||||||||||||||||||||
88 | |||||||||||||||||||||||||
89 | |||||||||||||||||||||||||
90 | |||||||||||||||||||||||||
91 | |||||||||||||||||||||||||
92 | |||||||||||||||||||||||||
93 | |||||||||||||||||||||||||
94 | |||||||||||||||||||||||||
95 | |||||||||||||||||||||||||
96 | |||||||||||||||||||||||||
97 | |||||||||||||||||||||||||
98 | |||||||||||||||||||||||||
99 | |||||||||||||||||||||||||
100 | |||||||||||||||||||||||||
101 | |||||||||||||||||||||||||
102 | |||||||||||||||||||||||||
103 | |||||||||||||||||||||||||
104 | |||||||||||||||||||||||||
105 | |||||||||||||||||||||||||
106 | |||||||||||||||||||||||||
107 | |||||||||||||||||||||||||
108 | |||||||||||||||||||||||||
109 | |||||||||||||||||||||||||
110 | |||||||||||||||||||||||||
111 | |||||||||||||||||||||||||
112 | |||||||||||||||||||||||||
113 | |||||||||||||||||||||||||
114 | |||||||||||||||||||||||||
115 | |||||||||||||||||||||||||
116 | |||||||||||||||||||||||||
117 | |||||||||||||||||||||||||
118 | |||||||||||||||||||||||||
119 | |||||||||||||||||||||||||
120 | |||||||||||||||||||||||||
121 | |||||||||||||||||||||||||
122 | |||||||||||||||||||||||||
123 | |||||||||||||||||||||||||
124 | |||||||||||||||||||||||||
125 | |||||||||||||||||||||||||
126 | |||||||||||||||||||||||||
127 | |||||||||||||||||||||||||
128 | |||||||||||||||||||||||||
129 | |||||||||||||||||||||||||
130 | |||||||||||||||||||||||||
131 | |||||||||||||||||||||||||
132 | |||||||||||||||||||||||||
133 | |||||||||||||||||||||||||
134 | |||||||||||||||||||||||||
135 | |||||||||||||||||||||||||
136 | |||||||||||||||||||||||||
137 | |||||||||||||||||||||||||
138 | |||||||||||||||||||||||||
139 | |||||||||||||||||||||||||
140 | |||||||||||||||||||||||||
141 | |||||||||||||||||||||||||
142 | |||||||||||||||||||||||||
143 | |||||||||||||||||||||||||
144 | |||||||||||||||||||||||||
145 | |||||||||||||||||||||||||
146 | |||||||||||||||||||||||||
147 | |||||||||||||||||||||||||
148 | |||||||||||||||||||||||||
149 | |||||||||||||||||||||||||
150 | |||||||||||||||||||||||||
151 | |||||||||||||||||||||||||
152 | |||||||||||||||||||||||||
153 | |||||||||||||||||||||||||
154 | |||||||||||||||||||||||||
155 | |||||||||||||||||||||||||
156 | |||||||||||||||||||||||||
157 | |||||||||||||||||||||||||
158 | |||||||||||||||||||||||||
159 | |||||||||||||||||||||||||
160 | |||||||||||||||||||||||||
161 | |||||||||||||||||||||||||
162 | |||||||||||||||||||||||||
163 | |||||||||||||||||||||||||
164 | |||||||||||||||||||||||||
165 | |||||||||||||||||||||||||
166 |