Skip to content

Commit 08f7eb4

Browse files
committed
implement multi-user support
1 parent 5ea47ca commit 08f7eb4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+865
-533
lines changed

features/test-implementations/1.setup.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ Given<TestWorld>(/logged in apify console user/i, async function () {
193193
}
194194

195195
// Try to make the client with the token
196-
const client = new ApifyClient(getApifyClientOptions(process.env.TEST_USER_TOKEN));
196+
const client = new ApifyClient(await getApifyClientOptions(process.env.TEST_USER_TOKEN));
197197

198198
try {
199199
await client.user('me').get();

src/commands/actor/charge.ts

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
import { APIFY_ENV_VARS } from '@apify/consts';
22

3-
import { getApifyTokenFromEnvOrAuthFile } from '../../lib/actor.js';
43
import { ApifyCommand } from '../../lib/command-framework/apify-command.js';
54
import { Args } from '../../lib/command-framework/args.js';
65
import { Flags } from '../../lib/command-framework/flags.js';
76
import { info } from '../../lib/outputs.js';
8-
import { getLoggedClient } from '../../lib/utils.js';
97

108
/**
119
* This command can be used to charge for a specific event in the pay-per-event Actor run.
@@ -45,6 +43,8 @@ export class ActorChargeCommand extends ApifyCommand<typeof ActorChargeCommand>
4543
}),
4644
};
4745

46+
static override requiresAuthentication = 'always' as const;
47+
4848
async run() {
4949
const { eventName } = this.args;
5050
const { count, testPayPerEvent, idempotencyKey } = this.flags;
@@ -67,18 +67,13 @@ export class ActorChargeCommand extends ApifyCommand<typeof ActorChargeCommand>
6767
return;
6868
}
6969

70-
const apifyToken = await getApifyTokenFromEnvOrAuthFile();
71-
const apifyClient = await getLoggedClient(apifyToken);
72-
if (!apifyClient) {
73-
throw new Error('Apify token is not set. Please set it using the environment variable APIFY_TOKEN.');
74-
}
7570
const runId = process.env[APIFY_ENV_VARS.ACTOR_RUN_ID];
7671

7772
if (!runId) {
7873
throw new Error('Charge command must be executed in a running Actor. Run ID not found.');
7974
}
8075

81-
const run = await apifyClient.run(runId).get();
76+
const run = await this.apifyClient.run(runId).get();
8277
if (run?.pricingInfo?.pricingModel !== 'PAY_PER_EVENT') {
8378
throw new Error('Charge command can only be used with pay-per-event pricing model.');
8479
}
@@ -87,7 +82,7 @@ export class ActorChargeCommand extends ApifyCommand<typeof ActorChargeCommand>
8782
message: `Charging ${count} events of type "${eventName}" with idempotency key "${idempotencyKey ?? 'not-provided'}" (runId: ${runId}).`,
8883
stdout: true,
8984
});
90-
await apifyClient.run(runId).charge({
85+
await this.apifyClient.run(runId).charge({
9186
eventName,
9287
count,
9388
idempotencyKey,

src/commands/actor/get-input.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ export class ActorGetInputCommand extends ApifyCommand<typeof ActorGetInputComma
77
static override description =
88
'Gets the Actor input value from the default key-value store associated with the Actor run.';
99

10+
static override requiresAuthentication = 'optionally' as const;
11+
1012
async run() {
11-
await outputInputFromDefaultStore();
13+
await outputInputFromDefaultStore(this.apifyClient);
1214
}
1315
}

src/commands/actor/get-public-url.ts

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
1-
import type { ApifyClient } from 'apify-client';
1+
import { ACTOR_ENV_VARS } from '@apify/consts';
22

3-
import { ACTOR_ENV_VARS, APIFY_ENV_VARS } from '@apify/consts';
4-
5-
import { getApifyStorageClient } from '../../lib/actor.js';
63
import { ApifyCommand } from '../../lib/command-framework/apify-command.js';
74
import { Args } from '../../lib/command-framework/args.js';
85
import { CommandExitCodes } from '../../lib/consts.js';
@@ -20,14 +17,11 @@ export class ActorGetPublicUrlCommand extends ApifyCommand<typeof ActorGetPublic
2017
}),
2118
};
2219

20+
static override requiresAuthentication = 'always' as const;
21+
2322
async run() {
2423
const { key } = this.args;
2524

26-
if ([undefined, 'false', ''].includes(process.env[APIFY_ENV_VARS.IS_AT_HOME])) {
27-
error({ message: 'get-public-url is not yet implemented for local development' });
28-
process.exitCode = CommandExitCodes.NotImplemented;
29-
return;
30-
}
3125
const storeId = process.env[ACTOR_ENV_VARS.DEFAULT_KEY_VALUE_STORE_ID];
3226

3327
// This should never happen, but handle it gracefully to prevent crashes.
@@ -39,8 +33,7 @@ export class ActorGetPublicUrlCommand extends ApifyCommand<typeof ActorGetPublic
3933
return;
4034
}
4135

42-
const apifyClient = (await getApifyStorageClient()) as ApifyClient;
43-
const store = await apifyClient.keyValueStore(storeId).get();
36+
const store = await this.apifyClient.keyValueStore(storeId).get();
4437

4538
if (!store) {
4639
error({
@@ -50,7 +43,7 @@ export class ActorGetPublicUrlCommand extends ApifyCommand<typeof ActorGetPublic
5043
return;
5144
}
5245

53-
const publicTarballUrl = await apifyClient.keyValueStore(storeId).getRecordPublicUrl(key);
46+
const publicTarballUrl = await this.apifyClient.keyValueStore(storeId).getRecordPublicUrl(key);
5447

5548
console.log(publicTarballUrl);
5649
}

src/commands/actor/get-value.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ export class ActorGetValueCommand extends ApifyCommand<typeof ActorGetValueComma
1414
}),
1515
};
1616

17+
static override requiresAuthentication = 'optionally' as const;
18+
1719
async run() {
1820
const { key } = this.args;
1921

20-
await outputRecordFromDefaultStore(key);
22+
await outputRecordFromDefaultStore(this.apifyClient, key);
2123
}
2224
}

src/commands/actor/push-data.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ export class ActorPushDataCommand extends ApifyCommand<typeof ActorPushDataComma
2222
}),
2323
};
2424

25+
static override requiresAuthentication = 'optionally' as const;
26+
2527
async run() {
2628
const { item: _item } = this.args;
2729

@@ -32,7 +34,7 @@ export class ActorPushDataCommand extends ApifyCommand<typeof ActorPushDataComma
3234
return;
3335
}
3436

35-
const apifyClient = await getApifyStorageClient();
37+
const apifyClient = await getApifyStorageClient(this.apifyClient);
3638
const defaultStoreId = getDefaultStorageId(APIFY_STORAGE_TYPES.DATASET);
3739

3840
let parsedData: Record<string, unknown> | Record<string, unknown>[];

src/commands/actor/set-value.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,15 @@ export class ActorSetValueCommand extends ApifyCommand<typeof ActorSetValueComma
3737
}),
3838
};
3939

40+
static override requiresAuthentication = 'optionally' as const;
41+
4042
async run() {
4143
const { key, value } = this.args;
4244
const { contentType = 'application/json; charset=utf-8' } = this.flags;
4345

4446
// NOTE: If user pass value as argument and data on stdin same time. We use the value from argument.
4547
const recordValue = value || process.stdin;
46-
const apifyClient = await getApifyStorageClient();
48+
const apifyClient = await getApifyStorageClient(this.apifyClient);
4749
const storeClient = apifyClient.keyValueStore(getDefaultStorageId(APIFY_STORAGE_TYPES.KEY_VALUE_STORE));
4850

4951
if (

src/commands/actors/call.ts

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,7 @@ import { getInputOverride } from '../../lib/commands/resolve-input.js';
1717
import { runActorOrTaskOnCloud, SharedRunOnCloudFlags } from '../../lib/commands/run-on-cloud.js';
1818
import { CommandExitCodes, LOCAL_CONFIG_PATH } from '../../lib/consts.js';
1919
import { error, simpleLog } from '../../lib/outputs.js';
20-
import {
21-
getLocalConfig,
22-
getLocalUserInfo,
23-
getLoggedClientOrThrow,
24-
printJsonToStdout,
25-
TimestampFormatter,
26-
} from '../../lib/utils.js';
20+
import { getLocalConfig, printJsonToStdout, TimestampFormatter } from '../../lib/utils.js';
2721

2822
export class ActorsCallCommand extends ApifyCommand<typeof ActorsCallCommand> {
2923
static override name = 'call' as const;
@@ -62,6 +56,7 @@ export class ActorsCallCommand extends ApifyCommand<typeof ActorsCallCommand> {
6256
};
6357

6458
static override enableJsonFlag = true;
59+
static override requiresAuthentication = 'always' as const;
6560

6661
static override args = {
6762
actorId: Args.string({
@@ -75,8 +70,7 @@ export class ActorsCallCommand extends ApifyCommand<typeof ActorsCallCommand> {
7570
async run() {
7671
const cwd = process.cwd();
7772
const localConfig = getLocalConfig(cwd) || {};
78-
const apifyClient = await getLoggedClientOrThrow();
79-
const userInfo = await getLocalUserInfo();
73+
const userInfo = await this.apifyClient.user().get();
8074
const usernameOrId = userInfo.username || (userInfo.id as string);
8175

8276
if (this.flags.json && this.flags.outputDataset) {
@@ -91,7 +85,7 @@ export class ActorsCallCommand extends ApifyCommand<typeof ActorsCallCommand> {
9185
userFriendlyId,
9286
actorData,
9387
} = await ActorsCallCommand.resolveActorId({
94-
client: apifyClient,
88+
client: this.apifyClient,
9589
localActorName: localConfig.name as string | undefined,
9690
usernameOrId,
9791
providedActorNameOrId: this.args.actorId,
@@ -126,7 +120,7 @@ export class ActorsCallCommand extends ApifyCommand<typeof ActorsCallCommand> {
126120
let url: string;
127121
let datasetUrl: string;
128122

129-
const iterator = runActorOrTaskOnCloud(apifyClient, {
123+
const iterator = runActorOrTaskOnCloud(this.apifyClient, {
130124
actorOrTaskData: {
131125
id: actorId,
132126
userFriendlyId,
@@ -226,7 +220,7 @@ export class ActorsCallCommand extends ApifyCommand<typeof ActorsCallCommand> {
226220
// Why is this needed? Sometimes, when fetching the dataset info right after the run ends, the object doesn't have the stats up-to-date.
227221
// But sometimes it does!
228222
do {
229-
info = (await apifyClient.dataset(datasetId).get())!;
223+
info = (await this.apifyClient.dataset(datasetId).get())!;
230224

231225
if (info?.itemCount) {
232226
break;
@@ -237,7 +231,7 @@ export class ActorsCallCommand extends ApifyCommand<typeof ActorsCallCommand> {
237231
});
238232
} while (retries--);
239233

240-
const dataset = await apifyClient.dataset(datasetId).downloadItems(DownloadItemsFormat.JSON, {
234+
const dataset = await this.apifyClient.dataset(datasetId).downloadItems(DownloadItemsFormat.JSON, {
241235
clean: true,
242236
});
243237

src/commands/actors/info.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { Flags } from '../../lib/command-framework/flags.js';
77
import { resolveActorContext } from '../../lib/commands/resolve-actor-context.js';
88
import { CompactMode, ResponsiveTable } from '../../lib/commands/responsive-table.js';
99
import { error, simpleLog } from '../../lib/outputs.js';
10-
import { DurationFormatter, getLoggedClientOrThrow, printJsonToStdout, TimestampFormatter } from '../../lib/utils.js';
10+
import { DurationFormatter, printJsonToStdout, TimestampFormatter } from '../../lib/utils.js';
1111

1212
interface HydratedActorInfo extends Omit<Actor, 'taggedBuilds'> {
1313
taggedBuilds?: Record<string, ActorTaggedBuild & { build?: Build }>;
@@ -64,14 +64,15 @@ export class ActorsInfoCommand extends ApifyCommand<typeof ActorsInfoCommand> {
6464
}),
6565
};
6666

67+
static override requiresAuthentication = 'always' as const;
68+
6769
static override enableJsonFlag = true;
6870

6971
async run() {
7072
const { actorId } = this.args;
7173
const { readme, input, json } = this.flags;
7274

73-
const client = await getLoggedClientOrThrow();
74-
const ctx = await resolveActorContext({ providedActorNameOrId: actorId, client });
75+
const ctx = await resolveActorContext({ providedActorNameOrId: actorId, client: this.apifyClient });
7576

7677
if (!ctx.valid) {
7778
error({
@@ -82,8 +83,8 @@ export class ActorsInfoCommand extends ApifyCommand<typeof ActorsInfoCommand> {
8283
return;
8384
}
8485

85-
const actorInfo = (await client.actor(ctx.id).get())! as HydratedActorInfo;
86-
const actorMaker = await client.user(actorInfo.userId).get();
86+
const actorInfo = (await this.apifyClient.actor(ctx.id).get())! as HydratedActorInfo;
87+
const actorMaker = await this.apifyClient.user(actorInfo.userId).get();
8788

8889
actorInfo.actorMaker = actorMaker;
8990

@@ -93,7 +94,7 @@ export class ActorsInfoCommand extends ApifyCommand<typeof ActorsInfoCommand> {
9394
continue;
9495
}
9596

96-
const buildData = await client.build(taggedBuild.buildId).get();
97+
const buildData = await this.apifyClient.build(taggedBuild.buildId).get();
9798

9899
taggedBuild.build = buildData;
99100
}

src/commands/actors/ls.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import { CompactMode, kSkipColumn, ResponsiveTable } from '../../lib/commands/re
1111
import { info, simpleLog } from '../../lib/outputs.js';
1212
import {
1313
DateOnlyTimestampFormatter,
14-
getLoggedClientOrThrow,
1514
MultilineTimestampFormatter,
1615
printJsonToStdout,
1716
ShortDurationFormatter,
@@ -120,12 +119,12 @@ export class ActorsLsCommand extends ApifyCommand<typeof ActorsLsCommand> {
120119

121120
static override enableJsonFlag = true;
122121

122+
static override requiresAuthentication = 'always' as const;
123+
123124
async run() {
124125
const { desc, limit, offset, my, json } = this.flags;
125126

126-
const client = await getLoggedClientOrThrow();
127-
128-
const rawActorList = await client.actors().list({ limit, offset, desc, my });
127+
const rawActorList = await this.apifyClient.actors().list({ limit, offset, desc, my });
129128

130129
if (rawActorList.count === 0) {
131130
if (json) {
@@ -146,8 +145,8 @@ export class ActorsLsCommand extends ApifyCommand<typeof ActorsLsCommand> {
146145
...rawActorList,
147146
items: await Promise.all(
148147
rawActorList.items.map(async (actorData) => {
149-
const actor = await client.actor(actorData.id).get();
150-
const runs = await client
148+
const actor = await this.apifyClient.actor(actorData.id).get();
149+
const runs = await this.apifyClient
151150
.actor(actorData.id)
152151
.runs()
153152
.list({ desc: true, limit: 1 })

0 commit comments

Comments
 (0)