@kodelyth/line 2026.5.42 → 2026.6.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.
Files changed (90) hide show
  1. package/klaw.plugin.json +329 -2
  2. package/package.json +16 -4
  3. package/api.ts +0 -11
  4. package/channel-plugin-api.ts +0 -1
  5. package/contract-api.ts +0 -5
  6. package/index.ts +0 -53
  7. package/runtime-api.ts +0 -179
  8. package/secret-contract-api.ts +0 -4
  9. package/setup-api.ts +0 -2
  10. package/setup-entry.ts +0 -9
  11. package/src/account-helpers.ts +0 -16
  12. package/src/accounts.test.ts +0 -288
  13. package/src/accounts.ts +0 -187
  14. package/src/actions.ts +0 -61
  15. package/src/auto-reply-delivery.test.ts +0 -253
  16. package/src/auto-reply-delivery.ts +0 -200
  17. package/src/bindings.ts +0 -65
  18. package/src/bot-access.ts +0 -30
  19. package/src/bot-handlers.test.ts +0 -1094
  20. package/src/bot-handlers.ts +0 -620
  21. package/src/bot-message-context.test.ts +0 -420
  22. package/src/bot-message-context.ts +0 -586
  23. package/src/bot.ts +0 -66
  24. package/src/card-command.ts +0 -347
  25. package/src/channel-access-token.ts +0 -14
  26. package/src/channel-api.ts +0 -17
  27. package/src/channel-setup-status.contract.test.ts +0 -70
  28. package/src/channel-shared.ts +0 -48
  29. package/src/channel.logout.test.ts +0 -145
  30. package/src/channel.runtime.ts +0 -3
  31. package/src/channel.sendPayload.test.ts +0 -659
  32. package/src/channel.setup.ts +0 -11
  33. package/src/channel.status.test.ts +0 -63
  34. package/src/channel.ts +0 -155
  35. package/src/config-adapter.ts +0 -29
  36. package/src/config-schema.test.ts +0 -53
  37. package/src/config-schema.ts +0 -81
  38. package/src/download.test.ts +0 -164
  39. package/src/download.ts +0 -34
  40. package/src/flex-templates/basic-cards.ts +0 -395
  41. package/src/flex-templates/common.ts +0 -20
  42. package/src/flex-templates/media-control-cards.ts +0 -555
  43. package/src/flex-templates/message.ts +0 -13
  44. package/src/flex-templates/schedule-cards.ts +0 -467
  45. package/src/flex-templates/types.ts +0 -22
  46. package/src/flex-templates.ts +0 -32
  47. package/src/gateway.ts +0 -129
  48. package/src/group-keys.test.ts +0 -123
  49. package/src/group-keys.ts +0 -65
  50. package/src/group-policy.ts +0 -22
  51. package/src/markdown-to-line.test.ts +0 -348
  52. package/src/markdown-to-line.ts +0 -416
  53. package/src/message-cards.test.ts +0 -204
  54. package/src/monitor-durable.test.ts +0 -57
  55. package/src/monitor-durable.ts +0 -37
  56. package/src/monitor.lifecycle.test.ts +0 -499
  57. package/src/monitor.runtime.ts +0 -1
  58. package/src/monitor.ts +0 -507
  59. package/src/outbound-media.test.ts +0 -194
  60. package/src/outbound-media.ts +0 -120
  61. package/src/outbound.runtime.ts +0 -12
  62. package/src/outbound.ts +0 -427
  63. package/src/probe.contract.test.ts +0 -9
  64. package/src/probe.runtime.ts +0 -1
  65. package/src/probe.ts +0 -34
  66. package/src/quick-reply-fallback.ts +0 -10
  67. package/src/reply-chunks.test.ts +0 -180
  68. package/src/reply-chunks.ts +0 -110
  69. package/src/reply-payload-transform.test.ts +0 -392
  70. package/src/reply-payload-transform.ts +0 -317
  71. package/src/rich-menu.test.ts +0 -315
  72. package/src/rich-menu.ts +0 -326
  73. package/src/runtime.ts +0 -32
  74. package/src/send-receipt.ts +0 -32
  75. package/src/send.test.ts +0 -453
  76. package/src/send.ts +0 -531
  77. package/src/setup-core.ts +0 -149
  78. package/src/setup-runtime-api.ts +0 -9
  79. package/src/setup-surface.test.ts +0 -481
  80. package/src/setup-surface.ts +0 -229
  81. package/src/signature.test.ts +0 -34
  82. package/src/signature.ts +0 -24
  83. package/src/status.ts +0 -37
  84. package/src/template-messages.ts +0 -333
  85. package/src/types.ts +0 -130
  86. package/src/webhook-node.test.ts +0 -598
  87. package/src/webhook-node.ts +0 -155
  88. package/src/webhook-utils.ts +0 -10
  89. package/src/webhook.ts +0 -135
  90. package/tsconfig.json +0 -16
@@ -1,555 +0,0 @@
1
- import type {
2
- FlexBox,
3
- FlexBubble,
4
- FlexButton,
5
- FlexComponent,
6
- FlexImage,
7
- FlexText,
8
- } from "./types.js";
9
-
10
- /**
11
- * Create a media player card for Sonos, Spotify, Apple Music, etc.
12
- *
13
- * Editorial design: Album art hero with gradient overlay for text,
14
- * prominent now-playing indicator, refined playback controls.
15
- */
16
- export function createMediaPlayerCard(params: {
17
- title: string;
18
- subtitle?: string;
19
- source?: string;
20
- imageUrl?: string;
21
- isPlaying?: boolean;
22
- progress?: string;
23
- controls?: {
24
- previous?: { data: string };
25
- play?: { data: string };
26
- pause?: { data: string };
27
- next?: { data: string };
28
- };
29
- extraActions?: Array<{ label: string; data: string }>;
30
- }): FlexBubble {
31
- const { title, subtitle, source, imageUrl, isPlaying, progress, controls, extraActions } = params;
32
-
33
- // Track info section
34
- const trackInfo: FlexComponent[] = [
35
- {
36
- type: "text",
37
- text: title,
38
- weight: "bold",
39
- size: "xl",
40
- color: "#111111",
41
- wrap: true,
42
- } as FlexText,
43
- ];
44
-
45
- if (subtitle) {
46
- trackInfo.push({
47
- type: "text",
48
- text: subtitle,
49
- size: "md",
50
- color: "#666666",
51
- wrap: true,
52
- margin: "sm",
53
- } as FlexText);
54
- }
55
-
56
- // Status row with source and playing indicator
57
- const statusItems: FlexComponent[] = [];
58
-
59
- if (isPlaying !== undefined) {
60
- statusItems.push({
61
- type: "box",
62
- layout: "horizontal",
63
- contents: [
64
- {
65
- type: "box",
66
- layout: "vertical",
67
- contents: [],
68
- width: "8px",
69
- height: "8px",
70
- backgroundColor: isPlaying ? "#06C755" : "#CCCCCC",
71
- cornerRadius: "4px",
72
- } as FlexBox,
73
- {
74
- type: "text",
75
- text: isPlaying ? "Now Playing" : "Paused",
76
- size: "xs",
77
- color: isPlaying ? "#06C755" : "#888888",
78
- weight: "bold",
79
- margin: "sm",
80
- } as FlexText,
81
- ],
82
- alignItems: "center",
83
- } as FlexBox);
84
- }
85
-
86
- if (source) {
87
- statusItems.push({
88
- type: "text",
89
- text: source,
90
- size: "xs",
91
- color: "#AAAAAA",
92
- margin: statusItems.length > 0 ? "lg" : undefined,
93
- } as FlexText);
94
- }
95
-
96
- if (progress) {
97
- statusItems.push({
98
- type: "text",
99
- text: progress,
100
- size: "xs",
101
- color: "#888888",
102
- align: "end",
103
- flex: 1,
104
- } as FlexText);
105
- }
106
-
107
- const bodyContents: FlexComponent[] = [
108
- {
109
- type: "box",
110
- layout: "vertical",
111
- contents: trackInfo,
112
- } as FlexBox,
113
- ];
114
-
115
- if (statusItems.length > 0) {
116
- bodyContents.push({
117
- type: "box",
118
- layout: "horizontal",
119
- contents: statusItems,
120
- margin: "lg",
121
- alignItems: "center",
122
- } as FlexBox);
123
- }
124
-
125
- const bubble: FlexBubble = {
126
- type: "bubble",
127
- size: "mega",
128
- body: {
129
- type: "box",
130
- layout: "vertical",
131
- contents: bodyContents,
132
- paddingAll: "xl",
133
- backgroundColor: "#FFFFFF",
134
- },
135
- };
136
-
137
- // Album art hero
138
- if (imageUrl) {
139
- bubble.hero = {
140
- type: "image",
141
- url: imageUrl,
142
- size: "full",
143
- aspectRatio: "1:1",
144
- aspectMode: "cover",
145
- } as FlexImage;
146
- }
147
-
148
- // Control buttons in footer
149
- if (controls || extraActions?.length) {
150
- const footerContents: FlexComponent[] = [];
151
-
152
- // Main playback controls with refined styling
153
- if (controls) {
154
- const controlButtons: FlexComponent[] = [];
155
-
156
- if (controls.previous) {
157
- controlButtons.push({
158
- type: "button",
159
- action: {
160
- type: "postback",
161
- label: "⏮",
162
- data: controls.previous.data,
163
- },
164
- style: "secondary",
165
- flex: 1,
166
- height: "sm",
167
- } as FlexButton);
168
- }
169
-
170
- if (controls.play) {
171
- controlButtons.push({
172
- type: "button",
173
- action: {
174
- type: "postback",
175
- label: "▶",
176
- data: controls.play.data,
177
- },
178
- style: isPlaying ? "secondary" : "primary",
179
- flex: 1,
180
- height: "sm",
181
- margin: controls.previous ? "md" : undefined,
182
- } as FlexButton);
183
- }
184
-
185
- if (controls.pause) {
186
- controlButtons.push({
187
- type: "button",
188
- action: {
189
- type: "postback",
190
- label: "⏸",
191
- data: controls.pause.data,
192
- },
193
- style: isPlaying ? "primary" : "secondary",
194
- flex: 1,
195
- height: "sm",
196
- margin: controlButtons.length > 0 ? "md" : undefined,
197
- } as FlexButton);
198
- }
199
-
200
- if (controls.next) {
201
- controlButtons.push({
202
- type: "button",
203
- action: {
204
- type: "postback",
205
- label: "⏭",
206
- data: controls.next.data,
207
- },
208
- style: "secondary",
209
- flex: 1,
210
- height: "sm",
211
- margin: controlButtons.length > 0 ? "md" : undefined,
212
- } as FlexButton);
213
- }
214
-
215
- if (controlButtons.length > 0) {
216
- footerContents.push({
217
- type: "box",
218
- layout: "horizontal",
219
- contents: controlButtons,
220
- } as FlexBox);
221
- }
222
- }
223
-
224
- // Extra actions
225
- if (extraActions?.length) {
226
- footerContents.push({
227
- type: "box",
228
- layout: "horizontal",
229
- contents: extraActions.slice(0, 2).map(
230
- (action, index) =>
231
- ({
232
- type: "button",
233
- action: {
234
- type: "postback",
235
- label: action.label.slice(0, 15),
236
- data: action.data,
237
- },
238
- style: "secondary",
239
- flex: 1,
240
- height: "sm",
241
- margin: index > 0 ? "md" : undefined,
242
- }) as FlexButton,
243
- ),
244
- margin: "md",
245
- } as FlexBox);
246
- }
247
-
248
- if (footerContents.length > 0) {
249
- bubble.footer = {
250
- type: "box",
251
- layout: "vertical",
252
- contents: footerContents,
253
- paddingAll: "lg",
254
- backgroundColor: "#FAFAFA",
255
- };
256
- }
257
- }
258
-
259
- return bubble;
260
- }
261
-
262
- /**
263
- * Create an Apple TV remote card with a D-pad and control rows.
264
- */
265
- export function createAppleTvRemoteCard(params: {
266
- deviceName: string;
267
- status?: string;
268
- actionData: {
269
- up: string;
270
- down: string;
271
- left: string;
272
- right: string;
273
- select: string;
274
- menu: string;
275
- home: string;
276
- play: string;
277
- pause: string;
278
- volumeUp: string;
279
- volumeDown: string;
280
- mute: string;
281
- };
282
- }): FlexBubble {
283
- const { deviceName, status, actionData } = params;
284
-
285
- const headerContents: FlexComponent[] = [
286
- {
287
- type: "text",
288
- text: deviceName,
289
- weight: "bold",
290
- size: "xl",
291
- color: "#111111",
292
- wrap: true,
293
- } as FlexText,
294
- ];
295
-
296
- if (status) {
297
- headerContents.push({
298
- type: "text",
299
- text: status,
300
- size: "sm",
301
- color: "#666666",
302
- wrap: true,
303
- margin: "sm",
304
- } as FlexText);
305
- }
306
-
307
- const makeButton = (
308
- label: string,
309
- data: string,
310
- style: "primary" | "secondary" = "secondary",
311
- ): FlexButton => ({
312
- type: "button",
313
- action: {
314
- type: "postback",
315
- label,
316
- data,
317
- },
318
- style,
319
- height: "sm",
320
- flex: 1,
321
- });
322
-
323
- const dpadRows: FlexComponent[] = [
324
- {
325
- type: "box",
326
- layout: "horizontal",
327
- contents: [{ type: "filler" }, makeButton("↑", actionData.up), { type: "filler" }],
328
- } as FlexBox,
329
- {
330
- type: "box",
331
- layout: "horizontal",
332
- contents: [
333
- makeButton("←", actionData.left),
334
- makeButton("OK", actionData.select, "primary"),
335
- makeButton("→", actionData.right),
336
- ],
337
- margin: "md",
338
- } as FlexBox,
339
- {
340
- type: "box",
341
- layout: "horizontal",
342
- contents: [{ type: "filler" }, makeButton("↓", actionData.down), { type: "filler" }],
343
- margin: "md",
344
- } as FlexBox,
345
- ];
346
-
347
- const menuRow: FlexComponent = {
348
- type: "box",
349
- layout: "horizontal",
350
- contents: [makeButton("Menu", actionData.menu), makeButton("Home", actionData.home)],
351
- margin: "lg",
352
- } as FlexBox;
353
-
354
- const playbackRow: FlexComponent = {
355
- type: "box",
356
- layout: "horizontal",
357
- contents: [makeButton("Play", actionData.play), makeButton("Pause", actionData.pause)],
358
- margin: "md",
359
- } as FlexBox;
360
-
361
- const volumeRow: FlexComponent = {
362
- type: "box",
363
- layout: "horizontal",
364
- contents: [
365
- makeButton("Vol +", actionData.volumeUp),
366
- makeButton("Mute", actionData.mute),
367
- makeButton("Vol -", actionData.volumeDown),
368
- ],
369
- margin: "md",
370
- } as FlexBox;
371
-
372
- return {
373
- type: "bubble",
374
- size: "mega",
375
- body: {
376
- type: "box",
377
- layout: "vertical",
378
- contents: [
379
- {
380
- type: "box",
381
- layout: "vertical",
382
- contents: headerContents,
383
- } as FlexBox,
384
- {
385
- type: "separator",
386
- margin: "lg",
387
- color: "#EEEEEE",
388
- },
389
- ...dpadRows,
390
- menuRow,
391
- playbackRow,
392
- volumeRow,
393
- ],
394
- paddingAll: "xl",
395
- backgroundColor: "#FFFFFF",
396
- },
397
- };
398
- }
399
-
400
- /**
401
- * Create a device control card for Apple TV, smart home devices, etc.
402
- *
403
- * Editorial design: Device-focused header with status indicator,
404
- * clean control grid with clear visual hierarchy.
405
- */
406
- export function createDeviceControlCard(params: {
407
- deviceName: string;
408
- deviceType?: string;
409
- status?: string;
410
- isOnline?: boolean;
411
- imageUrl?: string;
412
- controls: Array<{
413
- label: string;
414
- icon?: string;
415
- data: string;
416
- style?: "primary" | "secondary";
417
- }>;
418
- }): FlexBubble {
419
- const { deviceName, deviceType, status, isOnline, imageUrl, controls } = params;
420
-
421
- // Device header with status indicator
422
- const headerContents: FlexComponent[] = [
423
- {
424
- type: "box",
425
- layout: "horizontal",
426
- contents: [
427
- // Status dot
428
- {
429
- type: "box",
430
- layout: "vertical",
431
- contents: [],
432
- width: "10px",
433
- height: "10px",
434
- backgroundColor: isOnline !== false ? "#06C755" : "#FF5555",
435
- cornerRadius: "5px",
436
- } as FlexBox,
437
- {
438
- type: "text",
439
- text: deviceName,
440
- weight: "bold",
441
- size: "xl",
442
- color: "#111111",
443
- wrap: true,
444
- flex: 1,
445
- margin: "md",
446
- } as FlexText,
447
- ],
448
- alignItems: "center",
449
- } as FlexBox,
450
- ];
451
-
452
- if (deviceType) {
453
- headerContents.push({
454
- type: "text",
455
- text: deviceType,
456
- size: "sm",
457
- color: "#888888",
458
- margin: "sm",
459
- } as FlexText);
460
- }
461
-
462
- if (status) {
463
- headerContents.push({
464
- type: "box",
465
- layout: "vertical",
466
- contents: [
467
- {
468
- type: "text",
469
- text: status,
470
- size: "sm",
471
- color: "#444444",
472
- wrap: true,
473
- } as FlexText,
474
- ],
475
- margin: "lg",
476
- paddingAll: "md",
477
- backgroundColor: "#F8F9FA",
478
- cornerRadius: "md",
479
- } as FlexBox);
480
- }
481
-
482
- const bubble: FlexBubble = {
483
- type: "bubble",
484
- size: "mega",
485
- body: {
486
- type: "box",
487
- layout: "vertical",
488
- contents: headerContents,
489
- paddingAll: "xl",
490
- backgroundColor: "#FFFFFF",
491
- },
492
- };
493
-
494
- if (imageUrl) {
495
- bubble.hero = {
496
- type: "image",
497
- url: imageUrl,
498
- size: "full",
499
- aspectRatio: "16:9",
500
- aspectMode: "cover",
501
- } as FlexImage;
502
- }
503
-
504
- // Control buttons in refined grid layout (2 per row)
505
- if (controls.length > 0) {
506
- const rows: FlexComponent[] = [];
507
- const limitedControls = controls.slice(0, 6);
508
-
509
- for (let i = 0; i < limitedControls.length; i += 2) {
510
- const rowButtons: FlexComponent[] = [];
511
-
512
- for (let j = i; j < Math.min(i + 2, limitedControls.length); j++) {
513
- const ctrl = limitedControls[j];
514
- const buttonLabel = ctrl.icon ? `${ctrl.icon} ${ctrl.label}` : ctrl.label;
515
-
516
- rowButtons.push({
517
- type: "button",
518
- action: {
519
- type: "postback",
520
- label: buttonLabel.slice(0, 18),
521
- data: ctrl.data,
522
- },
523
- style: ctrl.style ?? "secondary",
524
- flex: 1,
525
- height: "sm",
526
- margin: j > i ? "md" : undefined,
527
- } as FlexButton);
528
- }
529
-
530
- // If odd number of controls in last row, add spacer
531
- if (rowButtons.length === 1) {
532
- rowButtons.push({
533
- type: "filler",
534
- });
535
- }
536
-
537
- rows.push({
538
- type: "box",
539
- layout: "horizontal",
540
- contents: rowButtons,
541
- margin: i > 0 ? "md" : undefined,
542
- } as FlexBox);
543
- }
544
-
545
- bubble.footer = {
546
- type: "box",
547
- layout: "vertical",
548
- contents: rows,
549
- paddingAll: "lg",
550
- backgroundColor: "#FAFAFA",
551
- };
552
- }
553
-
554
- return bubble;
555
- }
@@ -1,13 +0,0 @@
1
- import type { messagingApi } from "@line/bot-sdk";
2
- import type { FlexContainer } from "./types.js";
3
-
4
- /**
5
- * Wrap a FlexContainer in a FlexMessage
6
- */
7
- export function toFlexMessage(altText: string, contents: FlexContainer): messagingApi.FlexMessage {
8
- return {
9
- type: "flex",
10
- altText,
11
- contents,
12
- };
13
- }