Skip to content

Commit dc9e0d6

Browse files
Add admin webhook commands
1 parent 01449bf commit dc9e0d6

8 files changed

Lines changed: 270 additions & 2 deletions

File tree

‎package.json‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@linkedapi/linkedin-cli",
3-
"version": "1.0.17",
3+
"version": "1.1.0",
44
"description": "AI-agent-friendly CLI for controlling LinkedIn accounts and retrieving real-time data.",
55
"author": "Linked API",
66
"license": "MIT",
@@ -43,7 +43,7 @@
4343
"ai-agent"
4444
],
4545
"dependencies": {
46-
"@linkedapi/node": "^2.0.4",
46+
"@linkedapi/node": "^2.1.0",
4747
"@oclif/core": "^4.2.10"
4848
},
4949
"devDependencies": {
@@ -120,6 +120,9 @@
120120
},
121121
"admin:limits": {
122122
"description": "Configure and monitor rate limits"
123+
},
124+
"admin:webhook": {
125+
"description": "Manage the outbound event webhook and inspect deliveries"
123126
}
124127
}
125128
},
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { Args } from '@oclif/core';
2+
3+
import { AdminBaseCommand } from '@admin-base-command';
4+
import { formatAdminVoidOutput } from '@core/output/admin-formatter';
5+
6+
export default class WebhookDelete extends AdminBaseCommand {
7+
static override description =
8+
'Delete the webhook (soft-delete: delivery history is kept, pending deliveries are dropped)';
9+
10+
static override args = {
11+
id: Args.string({
12+
description: 'Webhook subscription id',
13+
required: true,
14+
}),
15+
};
16+
17+
static override flags = {
18+
...AdminBaseCommand.baseFlags,
19+
};
20+
21+
static override examples = ['<%= config.bin %> admin webhook delete whs-123'];
22+
23+
public async run(): Promise<void> {
24+
const { args, flags } = await this.parse(WebhookDelete);
25+
const admin = await this.buildAdminClient();
26+
27+
try {
28+
await admin.webhooks.delete({ id: args.id });
29+
30+
formatAdminVoidOutput({
31+
isJson: flags.json,
32+
isQuiet: flags.quiet,
33+
successMessage: 'Webhook deleted.',
34+
});
35+
} catch (error) {
36+
this.handleError(error);
37+
}
38+
}
39+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { AdminBaseCommand } from '@admin-base-command';
2+
import { formatAdminOutput } from '@core/output/admin-formatter';
3+
4+
export default class WebhookDeliveries extends AdminBaseCommand {
5+
static override description =
6+
'Show the most recent webhook deliveries (debug feed, newest first)';
7+
8+
static override flags = {
9+
...AdminBaseCommand.baseFlags,
10+
};
11+
12+
static override examples = ['<%= config.bin %> admin webhook deliveries'];
13+
14+
public async run(): Promise<void> {
15+
const { flags } = await this.parse(WebhookDeliveries);
16+
const admin = await this.buildAdminClient();
17+
18+
try {
19+
const deliveries = await admin.webhooks.deliveries();
20+
21+
formatAdminOutput({
22+
data: deliveries,
23+
isJson: flags.json,
24+
fields: flags.fields,
25+
});
26+
} catch (error) {
27+
this.handleError(error);
28+
}
29+
}
30+
}

‎src/commands/admin/webhook/get.ts‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { AdminBaseCommand } from '@admin-base-command';
2+
import { formatAdminOutput } from '@core/output/admin-formatter';
3+
4+
export default class WebhookGet extends AdminBaseCommand {
5+
static override description = 'List the active webhook subscription for this client';
6+
7+
static override flags = {
8+
...AdminBaseCommand.baseFlags,
9+
};
10+
11+
static override examples = ['<%= config.bin %> admin webhook get'];
12+
13+
public async run(): Promise<void> {
14+
const { flags } = await this.parse(WebhookGet);
15+
const admin = await this.buildAdminClient();
16+
17+
try {
18+
const webhooks = await admin.webhooks.get();
19+
20+
formatAdminOutput({
21+
data: webhooks,
22+
isJson: flags.json,
23+
fields: flags.fields,
24+
});
25+
} catch (error) {
26+
this.handleError(error);
27+
}
28+
}
29+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { Args } from '@oclif/core';
2+
3+
import { AdminBaseCommand } from '@admin-base-command';
4+
import { formatAdminVoidOutput } from '@core/output/admin-formatter';
5+
6+
export default class WebhookReplay extends AdminBaseCommand {
7+
static override description =
8+
'Re-arm an already-settled delivery for redelivery (reuses the same event id)';
9+
10+
static override args = {
11+
deliveryId: Args.string({
12+
description: 'Webhook delivery id (from `webhook deliveries`)',
13+
required: true,
14+
}),
15+
};
16+
17+
static override flags = {
18+
...AdminBaseCommand.baseFlags,
19+
};
20+
21+
static override examples = ['<%= config.bin %> admin webhook replay whd-123'];
22+
23+
public async run(): Promise<void> {
24+
const { args, flags } = await this.parse(WebhookReplay);
25+
const admin = await this.buildAdminClient();
26+
27+
try {
28+
await admin.webhooks.replayDelivery({ deliveryId: args.deliveryId });
29+
30+
formatAdminVoidOutput({
31+
isJson: flags.json,
32+
isQuiet: flags.quiet,
33+
successMessage: 'Redelivery queued.',
34+
});
35+
} catch (error) {
36+
this.handleError(error);
37+
}
38+
}
39+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { AdminBaseCommand } from '@admin-base-command';
2+
import { formatAdminVoidOutput } from '@core/output/admin-formatter';
3+
4+
export default class WebhookSendTest extends AdminBaseCommand {
5+
static override description =
6+
'Emit a synthetic webhook.test event to verify the endpoint end-to-end';
7+
8+
static override flags = {
9+
...AdminBaseCommand.baseFlags,
10+
};
11+
12+
static override examples = ['<%= config.bin %> admin webhook send-test'];
13+
14+
public async run(): Promise<void> {
15+
const { flags } = await this.parse(WebhookSendTest);
16+
const admin = await this.buildAdminClient();
17+
18+
try {
19+
await admin.webhooks.sendTest();
20+
21+
formatAdminVoidOutput({
22+
isJson: flags.json,
23+
isQuiet: flags.quiet,
24+
successMessage: 'Test event queued for delivery.',
25+
});
26+
} catch (error) {
27+
this.handleError(error);
28+
}
29+
}
30+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { Args } from '@oclif/core';
2+
import { TWebhookPayloadMode } from '@linkedapi/node';
3+
4+
import { AdminBaseCommand } from '@admin-base-command';
5+
import { formatAdminOutput } from '@core/output/admin-formatter';
6+
7+
export default class WebhookSetPayloadMode extends AdminBaseCommand {
8+
static override description = 'Switch the webhook payload mode between fat and thin';
9+
10+
static override args = {
11+
id: Args.string({
12+
description: 'Webhook subscription id',
13+
required: true,
14+
}),
15+
mode: Args.string({
16+
description: 'fat inlines the workflow result; thin sends a reference only',
17+
options: ['fat', 'thin'],
18+
required: true,
19+
}),
20+
};
21+
22+
static override flags = {
23+
...AdminBaseCommand.baseFlags,
24+
};
25+
26+
static override examples = ['<%= config.bin %> admin webhook set-payload-mode whs-123 thin'];
27+
28+
public async run(): Promise<void> {
29+
const { args, flags } = await this.parse(WebhookSetPayloadMode);
30+
const admin = await this.buildAdminClient();
31+
32+
try {
33+
const webhook = await admin.webhooks.setPayloadMode({
34+
id: args.id,
35+
payloadMode: args.mode as TWebhookPayloadMode,
36+
});
37+
38+
formatAdminOutput({
39+
data: webhook,
40+
isJson: flags.json,
41+
fields: flags.fields,
42+
});
43+
} catch (error) {
44+
this.handleError(error);
45+
}
46+
}
47+
}

‎src/commands/admin/webhook/set.ts‎

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { Args, Flags } from '@oclif/core';
2+
import { TWebhookPayloadMode } from '@linkedapi/node';
3+
4+
import { AdminBaseCommand } from '@admin-base-command';
5+
import { formatAdminOutput } from '@core/output/admin-formatter';
6+
7+
export default class WebhookSet extends AdminBaseCommand {
8+
static override description =
9+
'Register the outbound webhook that receives event deliveries (max one active per client)';
10+
11+
static override args = {
12+
url: Args.string({
13+
description: 'HTTPS endpoint that will receive event deliveries',
14+
required: true,
15+
}),
16+
};
17+
18+
static override flags = {
19+
...AdminBaseCommand.baseFlags,
20+
'payload-mode': Flags.string({
21+
description: 'fat inlines the workflow result; thin sends a reference to fetch via the API',
22+
options: ['fat', 'thin'],
23+
default: 'fat',
24+
}),
25+
};
26+
27+
static override examples = [
28+
'<%= config.bin %> admin webhook set https://example.com/hooks/linkedapi',
29+
'<%= config.bin %> admin webhook set https://example.com/hooks --payload-mode thin',
30+
];
31+
32+
public async run(): Promise<void> {
33+
const { args, flags } = await this.parse(WebhookSet);
34+
const admin = await this.buildAdminClient();
35+
36+
try {
37+
const webhook = await admin.webhooks.set({
38+
url: args.url,
39+
payloadMode: flags['payload-mode'] as TWebhookPayloadMode,
40+
});
41+
42+
formatAdminOutput({
43+
data: webhook,
44+
isJson: flags.json,
45+
fields: flags.fields,
46+
});
47+
} catch (error) {
48+
this.handleError(error);
49+
}
50+
}
51+
}

0 commit comments

Comments
 (0)