@algolia/wizard 0.8.0-rc.59.47 → 0.8.0-rc.62.50
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
|
@@ -907,7 +907,7 @@ var accessItems = [
|
|
|
907
907
|
{
|
|
908
908
|
tag: "READ",
|
|
909
909
|
title: "Project files",
|
|
910
|
-
description: "reads your dependency manifests (package.json\u2026), configs & source to detect your stack. Read-only; nothing is uploaded."
|
|
910
|
+
description: "reads your dependency manifests (package.json, pyproject.toml, Gemfile\u2026), configs & source to detect your stack. Read-only; nothing is uploaded."
|
|
911
911
|
},
|
|
912
912
|
{
|
|
913
913
|
tag: "WRITE",
|
|
@@ -2206,6 +2206,9 @@ function shellQuote(value) {
|
|
|
2206
2206
|
// src/lib/languages.ts
|
|
2207
2207
|
var ENTRYPOINT_TOKEN = "{entrypoint}";
|
|
2208
2208
|
var INGEST_DIR = ".algolia-wizard";
|
|
2209
|
+
var PY_VENV = `${INGEST_DIR}/.venv`;
|
|
2210
|
+
var PY_VENV_PYTHON = `${PY_VENV}/bin/python`;
|
|
2211
|
+
var PY_REQUIREMENTS = `${INGEST_DIR}/requirements.txt`;
|
|
2209
2212
|
var LANGUAGE_PROFILES = {
|
|
2210
2213
|
javascript: {
|
|
2211
2214
|
id: "javascript",
|
|
@@ -2248,6 +2251,151 @@ var LANGUAGE_PROFILES = {
|
|
|
2248
2251
|
verification: [],
|
|
2249
2252
|
envReadInstruction: "Read them from `process.env`.",
|
|
2250
2253
|
skipDirs: ["node_modules", "dist", "build", "coverage", ".next", "out"]
|
|
2254
|
+
},
|
|
2255
|
+
python: {
|
|
2256
|
+
id: "python",
|
|
2257
|
+
displayName: "Python",
|
|
2258
|
+
aliases: ["python", "python3", "py", "cpython"],
|
|
2259
|
+
manifests: [
|
|
2260
|
+
"pyproject.toml",
|
|
2261
|
+
"requirements.txt",
|
|
2262
|
+
"setup.py",
|
|
2263
|
+
"setup.cfg",
|
|
2264
|
+
"Pipfile"
|
|
2265
|
+
],
|
|
2266
|
+
// Deliberately one path for every Python repo: a wizard-owned venv under
|
|
2267
|
+
// .algolia-wizard. Reusing the project's uv/poetry environment would mean
|
|
2268
|
+
// mutating the developer's real dependency manifest and lockfile, and the
|
|
2269
|
+
// declare-here/install-there split is the main way ingestion silently ends
|
|
2270
|
+
// up without the SDK installed. The tradeoff: the script can import the
|
|
2271
|
+
// Algolia client and anything it declares itself, but not the project's own
|
|
2272
|
+
// packages (see the optional root-requirements step below).
|
|
2273
|
+
packageManagers: [
|
|
2274
|
+
{
|
|
2275
|
+
id: "pip-venv",
|
|
2276
|
+
dependency: { mode: "agent-declares", file: PY_REQUIREMENTS },
|
|
2277
|
+
installSteps: [
|
|
2278
|
+
{ argv: ["python3", "-m", "venv", PY_VENV] },
|
|
2279
|
+
{
|
|
2280
|
+
argv: [PY_VENV_PYTHON, "-m", "pip", "install", "-r", PY_REQUIREMENTS]
|
|
2281
|
+
},
|
|
2282
|
+
// Best-effort access to the project's own dependencies (DB drivers,
|
|
2283
|
+
// ORMs) when the repo pins them the classic way.
|
|
2284
|
+
{
|
|
2285
|
+
argv: [
|
|
2286
|
+
PY_VENV_PYTHON,
|
|
2287
|
+
"-m",
|
|
2288
|
+
"pip",
|
|
2289
|
+
"install",
|
|
2290
|
+
"-r",
|
|
2291
|
+
"requirements.txt"
|
|
2292
|
+
],
|
|
2293
|
+
requiresFile: "requirements.txt",
|
|
2294
|
+
optional: true
|
|
2295
|
+
}
|
|
2296
|
+
],
|
|
2297
|
+
ingest: {
|
|
2298
|
+
kind: "auto",
|
|
2299
|
+
argv: [PY_VENV_PYTHON, ENTRYPOINT_TOKEN],
|
|
2300
|
+
entrypointExtensions: [".py"]
|
|
2301
|
+
}
|
|
2302
|
+
}
|
|
2303
|
+
],
|
|
2304
|
+
sdk: {
|
|
2305
|
+
packageName: "algoliasearch",
|
|
2306
|
+
versionPin: ">=4,<5",
|
|
2307
|
+
docKey: "python"
|
|
2308
|
+
},
|
|
2309
|
+
ingestEntrypointExample: `${INGEST_DIR}/ingest.py`,
|
|
2310
|
+
localSourceCaveat: {
|
|
2311
|
+
unless: "requirements.txt",
|
|
2312
|
+
message: "The ingestion script runs in its own environment under .algolia-wizard/, so it can install the Algolia client but not this project's packages (no requirements.txt to install from). If the script needs your database driver or ORM, add those packages to .algolia-wizard/requirements.txt and re-run the install."
|
|
2313
|
+
},
|
|
2314
|
+
verification: [
|
|
2315
|
+
{
|
|
2316
|
+
// -x skips the venv this same directory holds; without it the check
|
|
2317
|
+
// compiles every installed package instead of the generated script.
|
|
2318
|
+
label: "python compileall",
|
|
2319
|
+
argv: ["python3", "-m", "compileall", "-q", "-x", "[.]venv", INGEST_DIR],
|
|
2320
|
+
requiresFile: INGEST_DIR
|
|
2321
|
+
}
|
|
2322
|
+
],
|
|
2323
|
+
envReadInstruction: "Read them from `os.environ`.",
|
|
2324
|
+
skipDirs: [
|
|
2325
|
+
"venv",
|
|
2326
|
+
"__pycache__",
|
|
2327
|
+
"site-packages",
|
|
2328
|
+
"dist",
|
|
2329
|
+
"build",
|
|
2330
|
+
"htmlcov"
|
|
2331
|
+
]
|
|
2332
|
+
},
|
|
2333
|
+
ruby: {
|
|
2334
|
+
id: "ruby",
|
|
2335
|
+
displayName: "Ruby",
|
|
2336
|
+
aliases: ["ruby", "rb", "rails", "ruby on rails", "rubyonrails"],
|
|
2337
|
+
manifests: ["Gemfile", "*.gemspec"],
|
|
2338
|
+
packageManagers: [
|
|
2339
|
+
{
|
|
2340
|
+
id: "bundler",
|
|
2341
|
+
dependency: { mode: "agent-declares", file: "Gemfile" },
|
|
2342
|
+
installSteps: [{ argv: ["bundle", "install"] }],
|
|
2343
|
+
ingest: {
|
|
2344
|
+
kind: "auto",
|
|
2345
|
+
argv: ["bundle", "exec", "ruby", ENTRYPOINT_TOKEN],
|
|
2346
|
+
entrypointExtensions: [".rb"]
|
|
2347
|
+
}
|
|
2348
|
+
}
|
|
2349
|
+
],
|
|
2350
|
+
sdk: { packageName: "algolia", versionPin: "~> 3.0", docKey: "ruby" },
|
|
2351
|
+
ingestEntrypointExample: `${INGEST_DIR}/ingest.rb`,
|
|
2352
|
+
// Ruby has no directory-level syntax check (`ruby -c` is one file at a
|
|
2353
|
+
// time), so verification relies on the agent's own review here.
|
|
2354
|
+
verification: [],
|
|
2355
|
+
envReadInstruction: "Read them from `ENV.fetch('NAME')`.",
|
|
2356
|
+
skipDirs: ["vendor", "tmp", "log", "coverage"]
|
|
2357
|
+
},
|
|
2358
|
+
php: {
|
|
2359
|
+
id: "php",
|
|
2360
|
+
displayName: "PHP",
|
|
2361
|
+
aliases: ["php", "laravel", "symfony"],
|
|
2362
|
+
manifests: ["composer.json"],
|
|
2363
|
+
packageManagers: [
|
|
2364
|
+
{
|
|
2365
|
+
id: "composer",
|
|
2366
|
+
// `composer require` both declares and installs, and unlike editing
|
|
2367
|
+
// composer.json by hand it can't leave composer.lock out of date (which
|
|
2368
|
+
// makes a later `composer install` refuse to run).
|
|
2369
|
+
dependency: { mode: "wizard-installs" },
|
|
2370
|
+
installSteps: [
|
|
2371
|
+
{
|
|
2372
|
+
argv: [
|
|
2373
|
+
"composer",
|
|
2374
|
+
"require",
|
|
2375
|
+
"algolia/algoliasearch-client-php:^4",
|
|
2376
|
+
"--no-interaction",
|
|
2377
|
+
// Repo post-install scripts are the project's code, not ours to
|
|
2378
|
+
// trigger; Laravel's package:discover also fails in a bare tree.
|
|
2379
|
+
"--no-scripts"
|
|
2380
|
+
]
|
|
2381
|
+
}
|
|
2382
|
+
],
|
|
2383
|
+
ingest: {
|
|
2384
|
+
kind: "auto",
|
|
2385
|
+
argv: ["php", ENTRYPOINT_TOKEN],
|
|
2386
|
+
entrypointExtensions: [".php"]
|
|
2387
|
+
}
|
|
2388
|
+
}
|
|
2389
|
+
],
|
|
2390
|
+
sdk: {
|
|
2391
|
+
packageName: "algolia/algoliasearch-client-php",
|
|
2392
|
+
versionPin: "^4",
|
|
2393
|
+
docKey: "php"
|
|
2394
|
+
},
|
|
2395
|
+
ingestEntrypointExample: `${INGEST_DIR}/ingest.php`,
|
|
2396
|
+
verification: [],
|
|
2397
|
+
envReadInstruction: "Read them from `getenv('NAME')`.",
|
|
2398
|
+
skipDirs: ["vendor", "node_modules"]
|
|
2251
2399
|
}
|
|
2252
2400
|
};
|
|
2253
2401
|
var DEFAULT_LANGUAGE_ID = "javascript";
|
|
@@ -2930,7 +3078,7 @@ var detectLanguageSchema = z16.object({
|
|
|
2930
3078
|
var detectLanguage = () => runAgent({
|
|
2931
3079
|
instructions: [
|
|
2932
3080
|
"Analyze the codebase and determine the programming languages and frameworks used",
|
|
2933
|
-
"Start from the dependency manifests: package.json.",
|
|
3081
|
+
"Start from the dependency manifests: package.json, pyproject.toml, requirements.txt, Gemfile, composer.json.",
|
|
2934
3082
|
"List the language that owns the backend/data code first \u2014 that is the one an ingestion script will be written in.",
|
|
2935
3083
|
"If a superset language is found, exclude the subset language. TS-over-JS.",
|
|
2936
3084
|
"If a meta-framework is used, exclude the framework. Next-over-React.",
|
|
@@ -2983,7 +3131,7 @@ var MODE_CONFIG = {
|
|
|
2983
3131
|
"Analyze the codebase to find the data entities (models) that should be ingested into Algolia.",
|
|
2984
3132
|
"For each entity, return its name, the file path(s) where it is defined, and its indexable attribute keys (the fields a user would search or filter on).",
|
|
2985
3133
|
"Inspect the source of each entity to extract real field names for attributes \u2014 do not guess or leave attributes empty.",
|
|
2986
|
-
"Entities live wherever the stack keeps them: TypeScript interfaces or a Prisma schema.",
|
|
3134
|
+
"Entities live wherever the stack keeps them: TypeScript interfaces or a Prisma schema, Django models.py, Rails app/models, Laravel Eloquent models, Pydantic models.",
|
|
2987
3135
|
"Prefer domain models (e.g. Document, Product, User) over framework or infrastructure types.",
|
|
2988
3136
|
"Use as few tools as possible, but do not guess. If you cannot find any entities, return an empty array.",
|
|
2989
3137
|
"Ignore directories that may be related to testing, like `/fixtures`, `/tests`, etc",
|
|
@@ -3006,8 +3154,8 @@ var MODE_CONFIG = {
|
|
|
3006
3154
|
verification: {
|
|
3007
3155
|
instructions: [
|
|
3008
3156
|
"Analyze the codebase to determine which code-quality tools are available to validate changes.",
|
|
3009
|
-
"Look at the dependency manifest and config files for the project's languages: package.json scripts with tsconfig/eslint/prettier.",
|
|
3010
|
-
'Return the tool names as an array, e.g. ["eslint", "prettier", "tsc"].',
|
|
3157
|
+
"Look at the dependency manifest and config files for the project's languages: package.json scripts with tsconfig/eslint/prettier, pyproject.toml or setup.cfg (ruff, mypy, black), Gemfile with .rubocop.yml, composer.json scripts (phpstan, pint).",
|
|
3158
|
+
'Return the tool names as an array, e.g. ["eslint", "prettier", "tsc"] or ["ruff", "mypy"].',
|
|
3011
3159
|
"Use as few tools as possible, but do not guess. If you cannot find any, return an empty array.",
|
|
3012
3160
|
"Ignore directories that may be related to testing, like `/fixtures`, `/tests`, etc",
|
|
3013
3161
|
"When done, call reportStatus"
|
|
@@ -3034,7 +3182,7 @@ async function runAnalysis(mode, extraInstructions = []) {
|
|
|
3034
3182
|
// package.json
|
|
3035
3183
|
var package_default = {
|
|
3036
3184
|
name: "@algolia/wizard",
|
|
3037
|
-
version: "0.8.0-rc.
|
|
3185
|
+
version: "0.8.0-rc.62.50",
|
|
3038
3186
|
description: "Magically implement Algolia functionality in your codebase",
|
|
3039
3187
|
type: "module",
|
|
3040
3188
|
engines: {
|
|
@@ -16,6 +16,9 @@ Install the latest stable within the major; never pin an exact patch.
|
|
|
16
16
|
| Language | Package | Version |
|
|
17
17
|
| --- | --- | --- |
|
|
18
18
|
| JavaScript/TypeScript | `algoliasearch` | `^5` |
|
|
19
|
+
| Python | `algoliasearch` | `>=4,<5` |
|
|
20
|
+
| Ruby | `algolia` | `~> 3.0` |
|
|
21
|
+
| PHP | `algolia/algoliasearch-client-php` | `^4` |
|
|
19
22
|
|
|
20
23
|
## Search UI
|
|
21
24
|
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Save records (algoliasearch-client-php v4)
|
|
2
|
+
|
|
3
|
+
Adds records to an index. Write op — use a **write key**, server-side only.
|
|
4
|
+
|
|
5
|
+
Dependency: `algolia/algoliasearch-client-php` `^4` — the wizard runs
|
|
6
|
+
`composer require` for you; do not hand-edit `composer.json`.
|
|
7
|
+
|
|
8
|
+
`require 'vendor/autoload.php'` before anything else, or the class won't resolve
|
|
9
|
+
(from `.algolia-wizard/` the path is `__DIR__.'/../vendor/autoload.php'`).
|
|
10
|
+
|
|
11
|
+
```php
|
|
12
|
+
<?php
|
|
13
|
+
|
|
14
|
+
require __DIR__.'/../vendor/autoload.php';
|
|
15
|
+
|
|
16
|
+
use Algolia\AlgoliaSearch\Api\SearchClient;
|
|
17
|
+
|
|
18
|
+
$appId = getenv('ALGOLIA_APPLICATION_ID');
|
|
19
|
+
$apiKey = getenv('ALGOLIA_WRITE_API_KEY');
|
|
20
|
+
$indexName = 'playlists';
|
|
21
|
+
|
|
22
|
+
$client = SearchClient::create($appId, $apiKey);
|
|
23
|
+
$records = [['objectID' => '1', 'name' => 'Hot 100', 'visibility' => 'public']];
|
|
24
|
+
|
|
25
|
+
$responses = $client->saveObjects($indexName, $records, true);
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
```php
|
|
29
|
+
saveObjects(
|
|
30
|
+
string $indexName, // required
|
|
31
|
+
array $objects, // required
|
|
32
|
+
bool $waitForTasks = false,
|
|
33
|
+
int $batchSize = 1000,
|
|
34
|
+
array $requestOptions = []
|
|
35
|
+
) // => array of batch responses, one per 1,000-record batch
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Unlike the typed clients, PHP returns **plain associative arrays**, not objects:
|
|
39
|
+
`$responses[0]['taskID']`, `$responses[0]['objectIDs']`. Always an array of them —
|
|
40
|
+
never treat it as one response.
|
|
41
|
+
|
|
42
|
+
Read records from a JSON file:
|
|
43
|
+
|
|
44
|
+
```php
|
|
45
|
+
$records = json_decode(file_get_contents($recordsPath), true);
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
After a successful ingest, print `ALGOLIA_WIZARD_RECORD_COUNT=<n>` as the last
|
|
49
|
+
stdout line (`echo 'ALGOLIA_WIZARD_RECORD_COUNT='.count($records)."\n";`), with no
|
|
50
|
+
other output after it.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Save records (algoliasearch v4)
|
|
2
|
+
|
|
3
|
+
Adds records to an index. Write op — use a **write key**, server-side only.
|
|
4
|
+
|
|
5
|
+
Dependency: `algoliasearch>=4,<5` (PyPI).
|
|
6
|
+
|
|
7
|
+
v4 is async-first: `SearchClient` is coroutine-based (every method needs `await`).
|
|
8
|
+
**`SearchClientSync` is the sync twin** — use it in a standalone script, via `with`
|
|
9
|
+
so the transport closes.
|
|
10
|
+
|
|
11
|
+
```python
|
|
12
|
+
import os
|
|
13
|
+
|
|
14
|
+
from algoliasearch.search.client import SearchClientSync
|
|
15
|
+
|
|
16
|
+
app_id = os.environ["ALGOLIA_APPLICATION_ID"]
|
|
17
|
+
api_key = os.environ["ALGOLIA_WRITE_API_KEY"]
|
|
18
|
+
index_name = "playlists"
|
|
19
|
+
records = [{"objectID": "1", "name": "Hot 100", "visibility": "public"}]
|
|
20
|
+
|
|
21
|
+
with SearchClientSync(app_id, api_key) as client:
|
|
22
|
+
responses = client.save_objects(
|
|
23
|
+
index_name=index_name,
|
|
24
|
+
objects=records,
|
|
25
|
+
wait_for_tasks=True,
|
|
26
|
+
)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
save_objects(
|
|
31
|
+
index_name: str, # required
|
|
32
|
+
objects: Iterable[Dict[str, Any]], # required
|
|
33
|
+
wait_for_tasks: bool = False,
|
|
34
|
+
batch_size: int = 1000,
|
|
35
|
+
) -> List[BatchResponse] # one entry per 1,000-record batch
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`BatchResponse` attributes are **snake_case**: `r.task_id`, `r.object_ids` (the
|
|
39
|
+
wire keys are `taskID`/`objectIDs`). It is a list — never treat it as one object.
|
|
40
|
+
|
|
41
|
+
Read records from a JSON file:
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
import json
|
|
45
|
+
|
|
46
|
+
with open(records_path, encoding="utf-8") as f:
|
|
47
|
+
records = json.load(f)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
After a successful ingest, print `ALGOLIA_WIZARD_RECORD_COUNT=<n>` as the last
|
|
51
|
+
stdout line.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Save records (algolia v3)
|
|
2
|
+
|
|
3
|
+
Adds records to an index. Write op — use a **write key**, server-side only.
|
|
4
|
+
|
|
5
|
+
Dependency: gem `algolia`, `~> 3.0` (`gem 'algolia', '~> 3.0'`).
|
|
6
|
+
|
|
7
|
+
`require "algolia"` (gem name is `algolia`, not `algoliasearch`). Build the client
|
|
8
|
+
with `Algolia::SearchClient.create`.
|
|
9
|
+
|
|
10
|
+
```ruby
|
|
11
|
+
require "algolia"
|
|
12
|
+
|
|
13
|
+
app_id = ENV.fetch("ALGOLIA_APPLICATION_ID")
|
|
14
|
+
api_key = ENV.fetch("ALGOLIA_WRITE_API_KEY")
|
|
15
|
+
index_name = "playlists"
|
|
16
|
+
|
|
17
|
+
client = Algolia::SearchClient.create(app_id, api_key)
|
|
18
|
+
|
|
19
|
+
records = [{ "objectID" => "1", "name" => "Hot 100", "visibility" => "public" }]
|
|
20
|
+
|
|
21
|
+
responses = client.save_objects(index_name, records, true)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
```ruby
|
|
25
|
+
save_objects(
|
|
26
|
+
index_name, # String, required
|
|
27
|
+
objects, # Array<Hash>, required
|
|
28
|
+
wait_for_tasks = false,
|
|
29
|
+
batch_size = 1000,
|
|
30
|
+
request_options = {}
|
|
31
|
+
) # => Array<Algolia::Search::BatchResponse>, one entry per 1,000-record batch
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Args are **positional**, and every method/field is **snake_case**: read
|
|
35
|
+
`r.task_id` and `r.object_ids`, not `taskID`/`objectIDs`. The return value is an
|
|
36
|
+
array — never treat it as one object.
|
|
37
|
+
|
|
38
|
+
Read records from a JSON file:
|
|
39
|
+
|
|
40
|
+
```ruby
|
|
41
|
+
require "json"
|
|
42
|
+
|
|
43
|
+
records = JSON.parse(File.read(records_path))
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
After a successful ingest, print `ALGOLIA_WIZARD_RECORD_COUNT=<n>` as the last
|
|
47
|
+
stdout line (`puts "ALGOLIA_WIZARD_RECORD_COUNT=#{records.length}"`), with no
|
|
48
|
+
other output after it.
|