@algolia/wizard 0.103.0-rc.217.760 → 0.103.0-rc.217.762
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.js
CHANGED
|
@@ -2467,7 +2467,7 @@ async function ensureApplication(resumeAppId) {
|
|
|
2467
2467
|
// package.json
|
|
2468
2468
|
var package_default = {
|
|
2469
2469
|
name: "@algolia/wizard",
|
|
2470
|
-
version: "0.103.0-rc.217.
|
|
2470
|
+
version: "0.103.0-rc.217.762",
|
|
2471
2471
|
description: "Magically implement Algolia functionality in your codebase",
|
|
2472
2472
|
type: "module",
|
|
2473
2473
|
engines: {
|
|
@@ -3216,6 +3216,18 @@ async function hasSymlinkParent(ctx, target) {
|
|
|
3216
3216
|
}
|
|
3217
3217
|
return false;
|
|
3218
3218
|
}
|
|
3219
|
+
var fileLocks = /* @__PURE__ */ new Map();
|
|
3220
|
+
async function withFileLock(target, fn) {
|
|
3221
|
+
const previous = fileLocks.get(target) ?? Promise.resolve();
|
|
3222
|
+
const run2 = previous.then(fn);
|
|
3223
|
+
const settled = run2.catch(() => void 0);
|
|
3224
|
+
fileLocks.set(target, settled);
|
|
3225
|
+
try {
|
|
3226
|
+
return await run2;
|
|
3227
|
+
} finally {
|
|
3228
|
+
if (fileLocks.get(target) === settled) fileLocks.delete(target);
|
|
3229
|
+
}
|
|
3230
|
+
}
|
|
3219
3231
|
function symlinkTargetError(target) {
|
|
3220
3232
|
return `Refused: ${target} is a symbolic link.`;
|
|
3221
3233
|
}
|
|
@@ -3464,7 +3476,10 @@ function writeFileTool(ctx) {
|
|
|
3464
3476
|
return secretEnvWriteRefusal(filePath);
|
|
3465
3477
|
}
|
|
3466
3478
|
try {
|
|
3467
|
-
const writeError = await
|
|
3479
|
+
const writeError = await withFileLock(
|
|
3480
|
+
resolved2.target,
|
|
3481
|
+
() => safeWriteFile(ctx, resolved2.target, content)
|
|
3482
|
+
);
|
|
3468
3483
|
if (writeError) return writeError;
|
|
3469
3484
|
useWizard.getState().recordWrittenFile(resolved2.target);
|
|
3470
3485
|
return `Wrote to ${filePath}`;
|
|
@@ -3530,29 +3545,31 @@ function editFileTool(ctx) {
|
|
|
3530
3545
|
return "Error: oldString and newString are identical. No change made.";
|
|
3531
3546
|
}
|
|
3532
3547
|
try {
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
3548
|
+
return await withFileLock(resolved2.target, async () => {
|
|
3549
|
+
const unsafe = await validateSafeWriteTarget(ctx, resolved2.target);
|
|
3550
|
+
if (unsafe) return unsafe;
|
|
3551
|
+
let content;
|
|
3552
|
+
try {
|
|
3553
|
+
content = await readFile5(resolved2.target, "utf8");
|
|
3554
|
+
} catch (err) {
|
|
3555
|
+
if (err.code === "ENOENT") {
|
|
3556
|
+
return `Error: ${filePath} does not exist. To create it, use writeFile.`;
|
|
3557
|
+
}
|
|
3558
|
+
throw err;
|
|
3541
3559
|
}
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
return matches > 1 ? `Edited ${filePath} (${matches} replacements)` : `Edited ${filePath}. ${editedSnippet(updated, content.indexOf(oldString), newString)}`;
|
|
3560
|
+
const matches = countOccurrences(content, oldString);
|
|
3561
|
+
if (matches === 0) {
|
|
3562
|
+
return `Error: oldString not found in ${filePath}. Read the file again and copy the exact text, including whitespace.`;
|
|
3563
|
+
}
|
|
3564
|
+
if (matches > 1 && !replaceAll) {
|
|
3565
|
+
return `Error: oldString matches ${matches} places in ${filePath}. Add surrounding lines to make it unique, or set replaceAll to true.`;
|
|
3566
|
+
}
|
|
3567
|
+
const updated = replaceAll ? content.split(oldString).join(newString) : replaceFirst(content, oldString, newString);
|
|
3568
|
+
const writeError = await safeWriteFile(ctx, resolved2.target, updated);
|
|
3569
|
+
if (writeError) return writeError;
|
|
3570
|
+
useWizard.getState().recordWrittenFile(resolved2.target);
|
|
3571
|
+
return matches > 1 ? `Edited ${filePath} (${matches} replacements)` : `Edited ${filePath}. ${editedSnippet(updated, content.indexOf(oldString), newString)}`;
|
|
3572
|
+
});
|
|
3556
3573
|
} catch (err) {
|
|
3557
3574
|
return `Error editing ${filePath}: ${err.message}`;
|
|
3558
3575
|
}
|
|
@@ -6745,6 +6762,7 @@ function searchInstructions(input) {
|
|
|
6745
6762
|
"Style the search surfaces through the widget's class and CSS-variable overrides (or, when hand-built, the app's existing theme tokens): give the results panel and the element that actually draws the input's border and background \u2014 for a widget, the form or wrapper it renders around the bare input \u2014 non-transparent surfaces, keep that frame distinguishable from the background behind it in every supported theme, and never assume a light surface or reuse the surrounding page's colors unchanged inside the panel.",
|
|
6746
6763
|
"The panel takes its width from the input by default, so a small input makes it unreadably narrow: give it `min-width: min(320px, calc(100vw - 2rem))` independent of the input, cap its maximum width to the viewport, and anchor it to the input edge it opens from so widening does not push it off-screen.",
|
|
6747
6764
|
"Match the application styles closely, including light, dark, and high-contrast themes the project already supports.",
|
|
6765
|
+
"Give the search input frame the same height, corner radius, border color and width, background, and focus style as the input it replaces. When it replaces nothing, copy them from the form controls beside it. Read these values from their source (the theme, the component props, or the CSS). Do not keep the widget theme defaults, for example a 44px height and 4px corners, and do not invent colors. When the app theme exists only in code, take the values from that theme object.",
|
|
6748
6766
|
"When you add UI text to a localized dictionary or message file, add the same keys, translated, to every locale the project supports.",
|
|
6749
6767
|
"Before reporting, mount the component. Do not run a type check, build, or test command unless a later instruction allows it: the validation pass runs the type check, after the developer agrees to it. If a tool limit is reached or an error remains unresolved, keep the implementation, report status=success, and name the remaining issue in the summary so validation can drive the next pass. Report status=fail only when no search implementation can be written, with the concrete blocker as the reason.",
|
|
6750
6768
|
"The summary should be extremely concise; do not mention manual testing steps."
|
|
@@ -6861,6 +6879,8 @@ function validationInstructions(input) {
|
|
|
6861
6879
|
"Find how the app selects each theme it supports (a class or attribute on an ancestor, a prefers-color-scheme media query, or a theme that exists only in code). Confirm that the search input and results panel take their colors from the active app theme through that same switch. A search widget whose colors do not match the page theme, for example a light panel on a dark page, is a failure: set sufficient=false.",
|
|
6862
6880
|
"When the project has a package.json, confirm that the theme CSS of the search widget (for InstantSearch, a theme from instantsearch.css) is imported once from a legal global-CSS entry for that framework (Next.js Pages Router: pages/_app; Next.js App Router: root layout; otherwise the app global stylesheet or a component module when allowed). If it is installed but not imported, or imported from a Next.js component file, set sufficient=false.",
|
|
6863
6881
|
"Confirm that the search component is reachable from and fits the corresponding content task at every supported breakpoint; require app-wide reachability only when the search scope is genuinely app-wide.",
|
|
6882
|
+
"For an InstantSearch Autocomplete, confirm that the item component (the React itemComponent, or the item template in indices[].templates) calls the onSelect that it receives when the user clicks the result, for example onClick={onSelect} on its root element. The widget goes to the getURL route only through onSelect: the click on its <li> only sends the Insights event. If the item ignores onSelect, set sufficient=false, because a click on a result then does nothing.",
|
|
6883
|
+
"Confirm that the search input frame has the same height, corner radius, border, and background as the input that it replaces, or as the form controls beside it when it replaces nothing. If the frame keeps the widget theme defaults or uses colors that the app does not use, set sufficient=false.",
|
|
6864
6884
|
"Do not run the test suite or any test command.",
|
|
6865
6885
|
"Do not modify files. Report each implementation issue as a concrete instruction for the next implementation pass.",
|
|
6866
6886
|
`Detected verification tools: ${JSON.stringify(input.findings.verification ?? [])}. Use only a type checker; ignore any linter or formatter in this list.`,
|
|
@@ -6875,7 +6895,7 @@ function validationInstructions(input) {
|
|
|
6875
6895
|
"Set sufficient=false when a required placement, accessibility, or theme-color property is observed to fail, the implementation is incomplete, or checks have implementation-caused failures; include concrete additionalInstructions for the next pass.",
|
|
6876
6896
|
"You can only read source files. If a required property can be checked in the source, check it there. If it can be established only in a browser (rendered contrast, keyboard behavior, 320-pixel reflow, live-region status, computed accessible name), set sufficient=true when the source shows no violation. Never request devtools, a screenshot, or a contrast tool, and never repeat a finding that an earlier pass already fixed.",
|
|
6877
6897
|
"If a check fails only in untouched code, set unrelatedFailure to a concise failure description.",
|
|
6878
|
-
"Set styleOnly=true when sufficient=false and every finding is one of these: the theme palette defaults remain, a palette override loses to the theme,
|
|
6898
|
+
"Set styleOnly=true when sufficient=false and every finding is one of these: the theme palette defaults remain, a palette override loses to the theme, the highlight classes keep the theme blue, or the input frame does not match the size, radius, border, or background of the controls that it must match. If any other finding exists, for example a light panel on a dark page or a result that a click does not open, do not set styleOnly.",
|
|
6879
6899
|
"Keep the summary to one short sentence. Put the details in additionalInstructions."
|
|
6880
6900
|
];
|
|
6881
6901
|
}
|
|
@@ -10145,7 +10165,7 @@ async function resetProjectState() {
|
|
|
10145
10165
|
// package.json with { type: 'json' }
|
|
10146
10166
|
var package_default2 = {
|
|
10147
10167
|
name: "@algolia/wizard",
|
|
10148
|
-
version: "0.103.0-rc.217.
|
|
10168
|
+
version: "0.103.0-rc.217.762",
|
|
10149
10169
|
description: "Magically implement Algolia functionality in your codebase",
|
|
10150
10170
|
type: "module",
|
|
10151
10171
|
engines: {
|
|
@@ -87,14 +87,15 @@ Ensure the attributes you map into the component match the entity. 'title' above
|
|
|
87
87
|
`searchParameters` (for example `['body:20']`), or as an index setting. Do both
|
|
88
88
|
for the same attribute names the template passes to Snippet.
|
|
89
89
|
|
|
90
|
-
### Navigation
|
|
90
|
+
### Navigation: `getURL` plus the template's `onSelect`
|
|
91
91
|
|
|
92
92
|
- `indices[].getURL` — `(item) => string`, a route that already exists; don't invent one.
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
- The `item` template
|
|
96
|
-
|
|
97
|
-
Insights `click`,
|
|
93
|
+
The widget goes there when `onSelect` runs: on Enter over a highlighted item, and on a
|
|
94
|
+
click only when the `item` template calls `onSelect`.
|
|
95
|
+
- The `item` template **must call the `onSelect` it is handed on click**, for example
|
|
96
|
+
`` html`<div onClick=${onSelect}>…</div>` ``. The widget's `<li>` click only sends the
|
|
97
|
+
Insights `click`. Without `onSelect`, a click on a result does nothing. No `<a>`, no
|
|
98
|
+
`href`, no other click handler, never `stopPropagation`.
|
|
98
99
|
- Do not pass a top-level `onSelect` to `autocomplete()` to navigate. `getURL` already
|
|
99
100
|
navigates.
|
|
100
101
|
- `getSearchPageURL` sends Enter with nothing highlighted to a full results page; pass it
|
|
@@ -287,8 +288,8 @@ insights: {
|
|
|
287
288
|
|
|
288
289
|
With `insights: true`, `autocomplete` sends `view` (on render) and `click` (from the
|
|
289
290
|
result element's own handler) itself. Its item template gets `{ item, onSelect }` and
|
|
290
|
-
**no `sendEvent`** — nothing to wire. Call `onSelect`
|
|
291
|
-
|
|
291
|
+
**no `sendEvent`** — nothing to wire. Call `onSelect` on click: it goes to
|
|
292
|
+
the `getURL` route and closes the panel. The click event fires either way.
|
|
292
293
|
|
|
293
294
|
`hits` and `infiniteHits` behave the same; only a custom `item` template whose click
|
|
294
295
|
target is your own element needs wiring — it gets `sendEvent` as the second argument.
|
|
@@ -79,14 +79,15 @@ Ensure the attributes you map into the component match the entity. 'title' above
|
|
|
79
79
|
`searchParameters` (for example `['body:20']`), or as an index setting. Do both
|
|
80
80
|
for the same attribute names the component passes to Snippet.
|
|
81
81
|
|
|
82
|
-
### Navigation
|
|
82
|
+
### Navigation: `getURL` plus the item's `onSelect`
|
|
83
83
|
|
|
84
84
|
- `indices[].getURL` — `(item) => string`, a route that already exists; don't invent one.
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
- `itemComponent`
|
|
88
|
-
|
|
89
|
-
|
|
85
|
+
The widget goes there when `onSelect` runs: on Enter over a highlighted item, and on a
|
|
86
|
+
click only when the item component calls `onSelect`.
|
|
87
|
+
- `itemComponent` **must call the `onSelect` it is handed on click**, for example
|
|
88
|
+
`<div onClick={onSelect}>`. The widget's `<li>` click only sends the Insights `click`.
|
|
89
|
+
Without `onSelect`, a click on a result does nothing. No `<a>`, no `href`, no other
|
|
90
|
+
`onClick`, never `stopPropagation`.
|
|
90
91
|
- Do not pass a top-level `onSelect` to `<Autocomplete>` (for example to call
|
|
91
92
|
`router.push`). `getURL` already navigates. The top-level callback can receive a
|
|
92
93
|
`SyntheticEvent` instead of `{ item }`, so reading `item` from it fails the type check.
|
|
@@ -281,8 +282,8 @@ policy allows it:
|
|
|
281
282
|
With `insights={true}`, `<Autocomplete>` sends `view` (on render) and `click` (from the
|
|
282
283
|
result element's own handler) itself. Its `itemComponent` receives
|
|
283
284
|
`{ item, onSelect, onApply }` and **no `sendEvent`** — nothing to wire. Call `onSelect`
|
|
284
|
-
|
|
285
|
-
|
|
285
|
+
on click: it goes to the `getURL` route and closes the panel. The click event fires
|
|
286
|
+
either way.
|
|
286
287
|
|
|
287
288
|
`<Hits>` and `<InfiniteHits>` behave the same way. Two cases there need explicit wiring:
|
|
288
289
|
|