feat: add actors search command to search Apify Store#1047
Conversation
Adds a new `actors search` subcommand that searches the Apify Store for Actors by query, category, author, pricing model, and more. Uses the apify-client SDK's StoreCollectionClient for consistency with all other commands. Does not require authentication. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
l2ysho
left a comment
There was a problem hiding this comment.
GJ, so far so good, just 2 small nits from me and we should also add some tests.
| process.exitCode = CommandExitCodes.RunFailed; | ||
| error({ | ||
| message: `Failed to search Apify Store: ${err instanceof Error ? err.message : String(err)}`, | ||
| stdout: true, |
There was a problem hiding this comment.
mmm, depends if we run this with --json i'd say. stdout for json=false, stderr for json=true + error object on stdout (or empty array)
Co-authored-by: Richard Solar <solar.richard@gmail.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
@l2ysho Thanks for the review. I added tests. :) |
l2ysho
left a comment
There was a problem hiding this comment.
lgtm, @patrikbraborec I found one corner case when testing, not sure how big problem it is so It is up to you if you want to tackle it here or we create separate issue. cc @vladfrangu
src/commands/actors/search.ts
Outdated
| const { query } = this.args; | ||
| const { json, sortBy, category, username, pricingModel, limit, offset } = this.flags; | ||
|
|
||
| const client = new ApifyClient(getApifyClientOptions()); |
There was a problem hiding this comment.
one sneaky problem here (as this is first non-auth API related command ). If user is authorised but his token is invalid (expired, revoked, ...) this command fail on 401.
example of test which should succeed but currently fail
describe('with expired/invalid token', () => {
useAuthSetup({ cleanup: true, perTest: true });
it('should still succeed when an invalid token is stored (no auth required)', async () => {
// Write a fake expired token to the auth file
const authPath = AUTH_FILE_PATH();
mkdirSync(dirname(authPath), { recursive: true });
writeFileSync(authPath, JSON.stringify({ token: 'fake-expired-token-12345' }));
await testRunCommand(ActorsSearchCommand, {
args_query: 'web scraper',
flags_json: true,
flags_limit: 1,
});
// This command should succeed without auth — but currently fails
// because getApifyClientOptions() injects the invalid token
expect(process.exitCode).toBeUndefined();
const output = lastLogMessage();
const parsed = JSON.parse(output);
expect(parsed).toHaveProperty('items');
});
});
this should be probably fixed inside of getApifyClientOptions but it may be to much noise for this PR and this hotfix is enough here:
const clientOptions = getApifyClientOptions();
delete clientOptions.token;
const client = new ApifyClient(clientOptions);
As I am not sure how long token lasts, this may not be so big problem but it is worth to know this can happen.
Summary
apify actors searchsubcommand that searches the Apify Store for Actors matching a queryapify-clientSDK (StoreCollectionClient) instead of rawfetchfor consistency with all other commands--jsonoutput flagTest plan
yarn dev:apify actors search "web scraper"and verify table outputyarn dev:apify actors search --category AI --limit 5 --jsonand verify JSON outputyarn dev:apify actors search --username apify --pricing-model FREEand verify filteringyarn dev:apify actors search "nonexistent-query-xyz"and verify empty result message🤖 Generated with Claude Code