@clankmates/cli 0.11.0 → 0.12.0

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.
@@ -1,3 +1,17 @@
1
+ import {
2
+ assertSinceFlags,
3
+ authenticatedActorKey,
4
+ cacheFlags,
5
+ cacheResult,
6
+ ownedPostsScope,
7
+ prepareCachePlan,
8
+ publicPostsScope,
9
+ saveCacheTimestamp,
10
+ sharedPostsScope,
11
+ type CachePlan,
12
+ type CacheResult,
13
+ type CacheScope,
14
+ } from "../lib/cache";
1
15
  import {
2
16
  booleanFlag,
3
17
  integerFlag,
@@ -50,52 +64,112 @@ export async function runPostCommand(args: ParsedArgs, io: Io): Promise<void> {
50
64
  }
51
65
 
52
66
  case "list": {
67
+ assertSinceFlags(args);
68
+ const channelId = await context.client.resolveChannelId(
69
+ requiredChannelFlag(args.flags),
70
+ );
71
+ const cacheScope = await maybeOwnedPostsScope(args, context, channelId);
72
+ const cachePlan = await maybePrepareCachePlan(args, context, cacheScope);
53
73
  const response = await context.client.listChannelPosts({
54
- channelId: await context.client.resolveChannelId(
55
- requiredChannelFlag(args.flags),
56
- ),
74
+ channelId,
57
75
  limit: integerFlag(args.flags, "limit", { label: "--limit" }),
58
76
  cursor: stringFlag(args.flags, "cursor"),
77
+ before: stringFlag(args.flags, "before"),
59
78
  order: parseLatestFirstOrder(stringFlag(args.flags, "order")),
60
- since: stringFlag(args.flags, "since"),
79
+ since: resolvedSince(args, cachePlan),
61
80
  });
81
+ const savedServerTimestamp = await maybeSaveCacheTimestamp(
82
+ args,
83
+ context,
84
+ cacheScope,
85
+ response.meta,
86
+ response.nextCursor === undefined,
87
+ );
62
88
 
63
- printPostCollection(args, context.outputMode, io, response);
89
+ printPostCollection(
90
+ args,
91
+ context.outputMode,
92
+ io,
93
+ response,
94
+ cacheResult(cachePlan, savedServerTimestamp),
95
+ );
64
96
  return;
65
97
  }
66
98
 
67
99
  case "public-list": {
100
+ assertSinceFlags(args);
101
+ const publicHandle = requiredPositional(
102
+ args.positionals,
103
+ 1,
104
+ "Missing public handle",
105
+ );
106
+ const channelName = requiredPositional(
107
+ args.positionals,
108
+ 2,
109
+ "Missing public channel name",
110
+ );
111
+ const cacheScope = maybePublicPostsScope(
112
+ args,
113
+ context,
114
+ publicHandle,
115
+ channelName,
116
+ );
117
+ const cachePlan = await maybePrepareCachePlan(args, context, cacheScope);
68
118
  const response = await context.client.listPublicChannelPosts({
69
- publicHandle: requiredPositional(
70
- args.positionals,
71
- 1,
72
- "Missing public handle",
73
- ),
74
- channelName: requiredPositional(
75
- args.positionals,
76
- 2,
77
- "Missing public channel name",
78
- ),
119
+ publicHandle,
120
+ channelName,
79
121
  limit: integerFlag(args.flags, "limit", { label: "--limit" }),
80
122
  cursor: stringFlag(args.flags, "cursor"),
123
+ before: stringFlag(args.flags, "before"),
81
124
  order: parseLatestFirstOrder(stringFlag(args.flags, "order")),
82
- since: stringFlag(args.flags, "since"),
125
+ since: resolvedSince(args, cachePlan),
83
126
  });
127
+ const savedServerTimestamp = await maybeSaveCacheTimestamp(
128
+ args,
129
+ context,
130
+ cacheScope,
131
+ response.meta,
132
+ response.nextCursor === undefined,
133
+ );
84
134
 
85
- printPostCollection(args, context.outputMode, io, response);
135
+ printPostCollection(
136
+ args,
137
+ context.outputMode,
138
+ io,
139
+ response,
140
+ cacheResult(cachePlan, savedServerTimestamp),
141
+ );
86
142
  return;
87
143
  }
88
144
 
89
145
  case "shared-list": {
146
+ assertSinceFlags(args);
147
+ const token = requiredPositional(args.positionals, 1, "Missing share token");
148
+ const cacheScope = maybeSharedPostsScope(args, context, token);
149
+ const cachePlan = await maybePrepareCachePlan(args, context, cacheScope);
90
150
  const response = await context.client.listSharedChannelPosts({
91
- token: requiredPositional(args.positionals, 1, "Missing share token"),
151
+ token,
92
152
  limit: integerFlag(args.flags, "limit", { label: "--limit" }),
93
153
  cursor: stringFlag(args.flags, "cursor"),
154
+ before: stringFlag(args.flags, "before"),
94
155
  order: parseLatestFirstOrder(stringFlag(args.flags, "order")),
95
- since: stringFlag(args.flags, "since"),
156
+ since: resolvedSince(args, cachePlan),
96
157
  });
158
+ const savedServerTimestamp = await maybeSaveCacheTimestamp(
159
+ args,
160
+ context,
161
+ cacheScope,
162
+ response.meta,
163
+ response.nextCursor === undefined,
164
+ );
97
165
 
98
- printPostCollection(args, context.outputMode, io, response);
166
+ printPostCollection(
167
+ args,
168
+ context.outputMode,
169
+ io,
170
+ response,
171
+ cacheResult(cachePlan, savedServerTimestamp),
172
+ );
99
173
  return;
100
174
  }
101
175
 
@@ -234,6 +308,7 @@ function printPostCollection(
234
308
  nextCursor?: string;
235
309
  meta?: Record<string, unknown>;
236
310
  },
311
+ cache?: CacheResult,
237
312
  ): void {
238
313
  if (outputMode === "json") {
239
314
  printJson(
@@ -242,6 +317,7 @@ function printPostCollection(
242
317
  items: response.items,
243
318
  nextCursor: response.nextCursor,
244
319
  meta: response.meta,
320
+ ...(cache ? { cache } : {}),
245
321
  }),
246
322
  );
247
323
  return;
@@ -267,6 +343,8 @@ function printPostCollection(
267
343
  if (message) {
268
344
  io.stdout(message);
269
345
  }
346
+
347
+ printCacheNote(io, cache);
270
348
  }
271
349
 
272
350
  function parseLatestFirstOrder(value: string | undefined): LatestFirstOrder | undefined {
@@ -281,6 +359,103 @@ function parseLatestFirstOrder(value: string | undefined): LatestFirstOrder | un
281
359
  throw new CliError("--order must be one of: latest, oldest", 2);
282
360
  }
283
361
 
362
+ async function maybePrepareCachePlan(
363
+ args: ParsedArgs,
364
+ context: Awaited<ReturnType<typeof createCommandContext>>,
365
+ scope: CacheScope | undefined,
366
+ ): Promise<CachePlan | undefined> {
367
+ return cacheFlags(args).sinceCache && scope
368
+ ? prepareCachePlan(context, scope)
369
+ : undefined;
370
+ }
371
+
372
+ async function maybeSaveCacheTimestamp(
373
+ args: ParsedArgs,
374
+ context: Awaited<ReturnType<typeof createCommandContext>>,
375
+ scope: CacheScope | undefined,
376
+ meta: Record<string, unknown> | undefined,
377
+ shouldSave: boolean,
378
+ ): Promise<string | undefined> {
379
+ return cacheFlags(args).saveCache && scope && shouldSave
380
+ ? saveCacheTimestamp(context, scope, meta)
381
+ : undefined;
382
+ }
383
+
384
+ async function maybeOwnedPostsScope(
385
+ args: ParsedArgs,
386
+ context: Awaited<ReturnType<typeof createCommandContext>>,
387
+ channelId: string,
388
+ ): Promise<CacheScope | undefined> {
389
+ if (!cacheFlags(args).sinceCache && !cacheFlags(args).saveCache) {
390
+ return undefined;
391
+ }
392
+
393
+ return ownedPostsScope({
394
+ context,
395
+ actorKey: await authenticatedActorKey(context),
396
+ channelId,
397
+ before: stringFlag(args.flags, "before"),
398
+ });
399
+ }
400
+
401
+ function maybePublicPostsScope(
402
+ args: ParsedArgs,
403
+ context: Awaited<ReturnType<typeof createCommandContext>>,
404
+ publicHandle: string,
405
+ channelName: string,
406
+ ): CacheScope | undefined {
407
+ if (!cacheFlags(args).sinceCache && !cacheFlags(args).saveCache) {
408
+ return undefined;
409
+ }
410
+
411
+ return publicPostsScope({
412
+ context,
413
+ publicHandle,
414
+ channelName,
415
+ before: stringFlag(args.flags, "before"),
416
+ });
417
+ }
418
+
419
+ function maybeSharedPostsScope(
420
+ args: ParsedArgs,
421
+ context: Awaited<ReturnType<typeof createCommandContext>>,
422
+ shareToken: string,
423
+ ): CacheScope | undefined {
424
+ if (!cacheFlags(args).sinceCache && !cacheFlags(args).saveCache) {
425
+ return undefined;
426
+ }
427
+
428
+ return sharedPostsScope({
429
+ context,
430
+ shareToken,
431
+ before: stringFlag(args.flags, "before"),
432
+ });
433
+ }
434
+
435
+ function resolvedSince(
436
+ args: ParsedArgs,
437
+ cachePlan: CachePlan | undefined,
438
+ ): string | undefined {
439
+ return stringFlag(args.flags, "since") ?? cachePlan?.previousServerTimestamp;
440
+ }
441
+
442
+ function printCacheNote(io: Io, cache: CacheResult | undefined): void {
443
+ if (!cache) {
444
+ return;
445
+ }
446
+
447
+ const details = [
448
+ cache.previousServerTimestamp
449
+ ? `used ${cache.previousServerTimestamp}`
450
+ : cache.hit
451
+ ? "used cache"
452
+ : "no cached timestamp",
453
+ cache.savedServerTimestamp ? `saved ${cache.savedServerTimestamp}` : undefined,
454
+ ].filter(Boolean);
455
+
456
+ io.stdout(`Cache: ${details.join("; ")}.`);
457
+ }
458
+
284
459
  function renderPostDetail(
285
460
  post: { id: string; attributes: PostAttributes },
286
461
  options: { title?: string; channelId?: string } = {},
package/src/lib/args.ts CHANGED
@@ -49,10 +49,21 @@ const CLI_OPTIONS = {
49
49
  "schema-stdin": { type: "boolean" },
50
50
  limit: { type: "string" },
51
51
  cursor: { type: "string" },
52
+ before: { type: "string" },
52
53
  order: { type: "string" },
53
54
  since: { type: "string" },
55
+ sinceCache: { type: "boolean" },
56
+ "since-cache": { type: "boolean" },
57
+ saveCache: { type: "boolean" },
58
+ "save-cache": { type: "boolean" },
54
59
  status: { type: "string" },
55
60
  mailbox: { type: "string" },
61
+ participant: { type: "string" },
62
+ participantScope: { type: "string" },
63
+ "participant-scope": { type: "string" },
64
+ query: { type: "string" },
65
+ hasAttachment: { type: "boolean" },
66
+ "has-attachment": { type: "boolean" },
56
67
  } as const;
57
68
 
58
69
  type ParsedValue = string | boolean;