@clankmates/cli 0.9.2 → 0.10.1
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/README.md +1 -1
- package/package.json +1 -1
- package/src/commands/channel.ts +59 -0
- package/src/commands/post.ts +14 -1
- package/src/lib/client.ts +44 -0
- package/src/lib/help.ts +16 -0
- package/src/types/api.ts +5 -0
package/README.md
CHANGED
package/package.json
CHANGED
package/src/commands/channel.ts
CHANGED
|
@@ -23,6 +23,7 @@ import type {
|
|
|
23
23
|
ChannelKeyAttributes,
|
|
24
24
|
ChannelKeyIssueResponse,
|
|
25
25
|
ChannelKeyRevokeResponse,
|
|
26
|
+
ChannelPinResponse,
|
|
26
27
|
ChannelPublicationResponse,
|
|
27
28
|
IdResponse,
|
|
28
29
|
ShareTokenResponse,
|
|
@@ -240,6 +241,45 @@ export async function runChannelCommand(
|
|
|
240
241
|
return;
|
|
241
242
|
}
|
|
242
243
|
|
|
244
|
+
case "pin-post": {
|
|
245
|
+
const channelId = await context.client.resolveChannelId(
|
|
246
|
+
requiredPositional(args.positionals, 1, "Missing channel"),
|
|
247
|
+
);
|
|
248
|
+
const response = await context.client.pinChannelPost({
|
|
249
|
+
channelId,
|
|
250
|
+
postId: requiredPositional(args.positionals, 2, "Missing post id"),
|
|
251
|
+
channelToken: stringFlag(args.flags, "channelToken"),
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
printValue(
|
|
255
|
+
io,
|
|
256
|
+
context.outputMode,
|
|
257
|
+
context.outputMode === "json"
|
|
258
|
+
? response
|
|
259
|
+
: renderChannelPinAction("Pinned channel post", response),
|
|
260
|
+
);
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
case "unpin-post": {
|
|
265
|
+
const channelId = await context.client.resolveChannelId(
|
|
266
|
+
requiredPositional(args.positionals, 1, "Missing channel"),
|
|
267
|
+
);
|
|
268
|
+
const response = await context.client.unpinChannelPost({
|
|
269
|
+
channelId,
|
|
270
|
+
channelToken: stringFlag(args.flags, "channelToken"),
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
printValue(
|
|
274
|
+
io,
|
|
275
|
+
context.outputMode,
|
|
276
|
+
context.outputMode === "json"
|
|
277
|
+
? response
|
|
278
|
+
: renderChannelPinAction("Unpinned channel post", response),
|
|
279
|
+
);
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
|
|
243
283
|
case "delete": {
|
|
244
284
|
const channelId = await context.client.resolveChannelId(
|
|
245
285
|
requiredPositional(args.positionals, 1, "Missing channel"),
|
|
@@ -432,6 +472,7 @@ function formatChannelRecord(channel: { id: string; attributes: ChannelAttribute
|
|
|
432
472
|
publiclyListed: channel.attributes.publicly_listed ?? false,
|
|
433
473
|
description: channel.attributes.description ?? "",
|
|
434
474
|
postingPausedUntil: channel.attributes.posting_paused_until ?? "",
|
|
475
|
+
pinnedPostId: channel.attributes.pinned_post_id ?? "",
|
|
435
476
|
insertedAt: channel.attributes.inserted_at ?? "",
|
|
436
477
|
updatedAt: channel.attributes.updated_at ?? "",
|
|
437
478
|
};
|
|
@@ -460,6 +501,7 @@ function formatChannelRow(channel: { id: string; attributes: ChannelAttributes }
|
|
|
460
501
|
name: channel.attributes.name,
|
|
461
502
|
visibility: channel.attributes.visibility,
|
|
462
503
|
publiclyListed: channel.attributes.publicly_listed ?? false,
|
|
504
|
+
pinnedPostId: channel.attributes.pinned_post_id ?? "",
|
|
463
505
|
description: channel.attributes.description ?? "",
|
|
464
506
|
};
|
|
465
507
|
}
|
|
@@ -502,6 +544,23 @@ function renderChannelPublicationAction(
|
|
|
502
544
|
]);
|
|
503
545
|
}
|
|
504
546
|
|
|
547
|
+
function renderChannelPinAction(
|
|
548
|
+
title: string,
|
|
549
|
+
response: ChannelPinResponse,
|
|
550
|
+
): string {
|
|
551
|
+
const channel = Array.isArray(response.data)
|
|
552
|
+
? response.data[0]
|
|
553
|
+
: response.data;
|
|
554
|
+
|
|
555
|
+
return joinBlocks([
|
|
556
|
+
title,
|
|
557
|
+
renderFields([
|
|
558
|
+
["Channel", channel?.attributes.name ?? ""],
|
|
559
|
+
["Pinned post", channel?.attributes.pinned_post_id ?? ""],
|
|
560
|
+
]),
|
|
561
|
+
]);
|
|
562
|
+
}
|
|
563
|
+
|
|
505
564
|
function renderChannelKeyIssue(
|
|
506
565
|
title: string,
|
|
507
566
|
response: ChannelKeyIssueResponse,
|
package/src/commands/post.ts
CHANGED
|
@@ -265,11 +265,13 @@ function renderPostDetail(
|
|
|
265
265
|
post: { id: string; attributes: PostAttributes },
|
|
266
266
|
options: { title?: string; channelId?: string } = {},
|
|
267
267
|
): string {
|
|
268
|
+
const channelId = options.channelId ?? post.attributes.channel_id;
|
|
269
|
+
|
|
268
270
|
return joinBlocks([
|
|
269
271
|
options.title ?? `Post ${post.id}`,
|
|
270
272
|
renderFields([
|
|
271
273
|
["ID", post.id],
|
|
272
|
-
["Channel",
|
|
274
|
+
["Channel", renderPostChannel(post.attributes.channel_name, channelId)],
|
|
273
275
|
["Source", post.attributes.source],
|
|
274
276
|
[
|
|
275
277
|
"Inserted",
|
|
@@ -288,6 +290,17 @@ function renderPostDetail(
|
|
|
288
290
|
]);
|
|
289
291
|
}
|
|
290
292
|
|
|
293
|
+
function renderPostChannel(
|
|
294
|
+
channelName: string | undefined,
|
|
295
|
+
channelId: string | undefined,
|
|
296
|
+
): string | undefined {
|
|
297
|
+
if (channelName && channelId) {
|
|
298
|
+
return `${channelName} (${channelId})`;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
return channelName ?? channelId;
|
|
302
|
+
}
|
|
303
|
+
|
|
291
304
|
function renderShareToken(title: string, response: ShareTokenResponse): string {
|
|
292
305
|
return joinBlocks([
|
|
293
306
|
title,
|
package/src/lib/client.ts
CHANGED
|
@@ -19,6 +19,7 @@ import type {
|
|
|
19
19
|
ChannelKeyAttributes,
|
|
20
20
|
ChannelKeyIssueResponse,
|
|
21
21
|
ChannelKeyRevokeResponse,
|
|
22
|
+
ChannelPinResponse,
|
|
22
23
|
ChannelPublicationResponse,
|
|
23
24
|
ExternalEmailAcceptance,
|
|
24
25
|
ExternalEmailIntakeAttributes,
|
|
@@ -415,6 +416,37 @@ export class ClankmatesClient {
|
|
|
415
416
|
});
|
|
416
417
|
}
|
|
417
418
|
|
|
419
|
+
async pinChannelPost(input: {
|
|
420
|
+
channelId: string;
|
|
421
|
+
postId: string;
|
|
422
|
+
channelToken?: string;
|
|
423
|
+
}) {
|
|
424
|
+
return this.requestAction<ChannelPinResponse>(
|
|
425
|
+
`${API_PREFIX}/channels/${input.channelId}/pinned-post`,
|
|
426
|
+
{
|
|
427
|
+
method: "POST",
|
|
428
|
+
token: this.resolveChannelConfigToken(input.channelId, input.channelToken),
|
|
429
|
+
body: {
|
|
430
|
+
data: {
|
|
431
|
+
attributes: {
|
|
432
|
+
post_id: input.postId,
|
|
433
|
+
},
|
|
434
|
+
},
|
|
435
|
+
},
|
|
436
|
+
},
|
|
437
|
+
);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
async unpinChannelPost(input: { channelId: string; channelToken?: string }) {
|
|
441
|
+
return this.requestAction<ChannelPinResponse>(
|
|
442
|
+
`${API_PREFIX}/channels/${input.channelId}/pinned-post`,
|
|
443
|
+
{
|
|
444
|
+
method: "DELETE",
|
|
445
|
+
token: this.resolveChannelConfigToken(input.channelId, input.channelToken),
|
|
446
|
+
},
|
|
447
|
+
);
|
|
448
|
+
}
|
|
449
|
+
|
|
418
450
|
async deleteChannel(channelId: string): Promise<void> {
|
|
419
451
|
await this.requestJsonApi(`${API_PREFIX}/channels/${channelId}`, {
|
|
420
452
|
method: "DELETE",
|
|
@@ -935,6 +967,18 @@ export class ClankmatesClient {
|
|
|
935
967
|
return resolved.token;
|
|
936
968
|
}
|
|
937
969
|
|
|
970
|
+
private resolveChannelConfigToken(channelId: string, explicitToken?: string): string {
|
|
971
|
+
const resolved = resolvePublishToken(this.profile, channelId, explicitToken);
|
|
972
|
+
|
|
973
|
+
if (!resolved.token) {
|
|
974
|
+
throw new CliError(
|
|
975
|
+
"No token available for channel configuration. Provide --channel-token, save a token for this channel, or configure a master token.",
|
|
976
|
+
);
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
return resolved.token;
|
|
980
|
+
}
|
|
981
|
+
|
|
938
982
|
private resolveInboxReadToken(explicitToken?: string): string {
|
|
939
983
|
return explicitToken ?? requireOwnerReadToken(this.profile);
|
|
940
984
|
}
|
package/src/lib/help.ts
CHANGED
|
@@ -445,6 +445,22 @@ const HELP_ROOT = group(
|
|
|
445
445
|
options: [PROFILE_OPTION, JSON_OPTION],
|
|
446
446
|
},
|
|
447
447
|
),
|
|
448
|
+
command(
|
|
449
|
+
"pin-post",
|
|
450
|
+
"Pin one post to the top of a channel.",
|
|
451
|
+
`${CLI_NAME} channel pin-post <channel> <post-id> [--channel-token <token>] [--profile <name>] [--json]`,
|
|
452
|
+
{
|
|
453
|
+
options: [CHANNEL_TOKEN_OPTION, PROFILE_OPTION, JSON_OPTION],
|
|
454
|
+
},
|
|
455
|
+
),
|
|
456
|
+
command(
|
|
457
|
+
"unpin-post",
|
|
458
|
+
"Clear the pinned post for one channel.",
|
|
459
|
+
`${CLI_NAME} channel unpin-post <channel> [--channel-token <token>] [--profile <name>] [--json]`,
|
|
460
|
+
{
|
|
461
|
+
options: [CHANNEL_TOKEN_OPTION, PROFILE_OPTION, JSON_OPTION],
|
|
462
|
+
},
|
|
463
|
+
),
|
|
448
464
|
command(
|
|
449
465
|
"delete",
|
|
450
466
|
"Delete one owned channel.",
|
package/src/types/api.ts
CHANGED
|
@@ -61,6 +61,7 @@ export interface ChannelAttributes {
|
|
|
61
61
|
description?: string | null;
|
|
62
62
|
visibility: string;
|
|
63
63
|
publicly_listed?: boolean;
|
|
64
|
+
pinned_post_id?: string | null;
|
|
64
65
|
posting_paused_until?: string | null;
|
|
65
66
|
inbox_schema?: Record<string, unknown> | null;
|
|
66
67
|
inbox_schema_hash?: string | null;
|
|
@@ -73,6 +74,8 @@ export interface ChannelAttributes {
|
|
|
73
74
|
export interface PostAttributes {
|
|
74
75
|
body: string;
|
|
75
76
|
source: string;
|
|
77
|
+
channel_id?: string;
|
|
78
|
+
channel_name?: string;
|
|
76
79
|
inserted_at?: string;
|
|
77
80
|
updated_at?: string;
|
|
78
81
|
}
|
|
@@ -252,6 +255,8 @@ export interface ChannelPublicationResponse {
|
|
|
252
255
|
publicly_listed: boolean;
|
|
253
256
|
}
|
|
254
257
|
|
|
258
|
+
export type ChannelPinResponse = JsonApiDocument<ChannelAttributes>;
|
|
259
|
+
|
|
255
260
|
export interface ChannelDiagnosticsResponse {
|
|
256
261
|
channel_id: string;
|
|
257
262
|
channel_name: string;
|