@khorsheed/dsh-reader 0.2.1 → 0.3.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 (89) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/README.en.md +26 -121
  3. package/README.i18n.yaml +3 -3
  4. package/README.md +26 -121
  5. package/cordis.patch.yml +7 -0
  6. package/lib/client.js +30580 -6892
  7. package/lib/index.js +4189 -621
  8. package/lib/typert.host.js +2265 -319
  9. package/lib/typert.remote-client.d.ts +99 -3
  10. package/lib/typert.remote-client.js +1618 -240
  11. package/lib/types/captions.d.ts +99 -0
  12. package/lib/types/captions.js +236 -0
  13. package/lib/types/client/MediaPlayer.d.ts +55 -0
  14. package/lib/types/client/MediaPlayer.js +106 -0
  15. package/lib/types/client/NotesView.d.ts +57 -0
  16. package/lib/types/client/NotesView.js +124 -0
  17. package/lib/types/client/ReaderPane.d.ts +20 -3
  18. package/lib/types/client/ReaderPane.js +905 -164
  19. package/lib/types/client/SpeakerLegend.d.ts +18 -0
  20. package/lib/types/client/SpeakerLegend.js +26 -0
  21. package/lib/types/client/canvas-sync.d.ts +84 -0
  22. package/lib/types/client/canvas-sync.js +59 -0
  23. package/lib/types/client/contract.d.ts +138 -3
  24. package/lib/types/client/extract-article.d.ts +38 -1
  25. package/lib/types/client/extract-article.js +501 -28
  26. package/lib/types/client/icons.d.ts +1 -1
  27. package/lib/types/client/icons.js +1 -1
  28. package/lib/types/client/index.js +82 -2
  29. package/lib/types/client/locales.d.ts +279 -11
  30. package/lib/types/client/locales.js +278 -10
  31. package/lib/types/client/notes.d.ts +142 -0
  32. package/lib/types/client/notes.js +334 -0
  33. package/lib/types/client/parse-rss.js +40 -0
  34. package/lib/types/client/preset-visibility.d.ts +93 -0
  35. package/lib/types/client/preset-visibility.js +115 -0
  36. package/lib/types/client/selectors.d.ts +5 -0
  37. package/lib/types/client/selectors.js +5 -0
  38. package/lib/types/client/session.d.ts +21 -1
  39. package/lib/types/client/session.js +12 -0
  40. package/lib/types/client/store.js +4 -1
  41. package/lib/types/client/translate.d.ts +26 -1
  42. package/lib/types/client/translate.js +29 -12
  43. package/lib/types/client/useLocalTranscript.d.ts +43 -0
  44. package/lib/types/client/useLocalTranscript.js +129 -0
  45. package/lib/types/client/useMedia.d.ts +68 -0
  46. package/lib/types/client/useMedia.js +299 -0
  47. package/lib/types/client/useMediaStates.d.ts +9 -0
  48. package/lib/types/client/useMediaStates.js +43 -0
  49. package/lib/types/client/useNotes.d.ts +110 -0
  50. package/lib/types/client/useNotes.js +423 -0
  51. package/lib/types/client/usePolish.d.ts +47 -0
  52. package/lib/types/client/usePolish.js +162 -0
  53. package/lib/types/image-fetch.d.ts +81 -0
  54. package/lib/types/image-fetch.js +385 -0
  55. package/lib/types/index.d.ts +6 -0
  56. package/lib/types/index.js +3 -0
  57. package/lib/types/local-transcribe.d.ts +171 -0
  58. package/lib/types/local-transcribe.js +473 -0
  59. package/lib/types/media-host.d.ts +91 -0
  60. package/lib/types/media-host.js +230 -0
  61. package/lib/types/media.d.ts +100 -0
  62. package/lib/types/media.js +207 -0
  63. package/lib/types/notes-types.d.ts +158 -0
  64. package/lib/types/notes-types.js +8 -0
  65. package/lib/types/notes.d.ts +213 -0
  66. package/lib/types/notes.js +718 -0
  67. package/lib/types/polish.d.ts +41 -0
  68. package/lib/types/polish.js +136 -0
  69. package/lib/types/remote.d.ts +127 -1
  70. package/lib/types/remote.js +162 -1
  71. package/lib/types/service.d.ts +100 -1
  72. package/lib/types/service.js +320 -59
  73. package/lib/types/skill.d.ts +20 -0
  74. package/lib/types/skill.js +78 -0
  75. package/lib/types/store.js +30 -8
  76. package/lib/types/tool.d.ts +23 -0
  77. package/lib/types/tool.js +40 -0
  78. package/lib/types/tools.d.ts +69 -0
  79. package/lib/types/tools.js +400 -0
  80. package/lib/types/types.d.ts +106 -0
  81. package/lib/types/types.js +66 -0
  82. package/lib/types/xiaoyuzhou.d.ts +43 -0
  83. package/lib/types/xiaoyuzhou.js +134 -0
  84. package/lib/types/ytdlp.d.ts +111 -0
  85. package/lib/types/ytdlp.js +269 -0
  86. package/package.json +29 -20
  87. package/lib/invariant.js +0 -38
  88. package/lib/types/invariant.d.ts +0 -29
  89. package/lib/types/invariant.js +0 -38
@@ -0,0 +1,41 @@
1
+ import type { ReaderPolishView } from './types.ts';
2
+ /**
3
+ * What a layer belongs to: the paragraphs' text without their time and
4
+ * speaker prefixes, hashed.
5
+ */
6
+ export declare function sourceKey(paragraphs: readonly string[]): string;
7
+ /**
8
+ * Parse the model's write-back: lines `¶12:译文…` (a line without a ¶
9
+ * continues the paragraph before it).
10
+ *
11
+ * @param text - what the model sent.
12
+ */
13
+ export declare function parsePolish(text: string): Map<number, string>;
14
+ /** The per-article 润色 layers. */
15
+ export declare class ReaderPolishStore {
16
+ private readonly dir;
17
+ private readonly memory;
18
+ constructor(stateRoot: string);
19
+ private fileOf;
20
+ private load;
21
+ private save;
22
+ /**
23
+ * An article's layer, when it belongs to the text now captured.
24
+ *
25
+ * @param entryId - the article.
26
+ * @param key - the current text's {@link sourceKey}.
27
+ */
28
+ view(entryId: string, key: string | undefined): ReaderPolishView | undefined;
29
+ /**
30
+ * Merge the model's translations into the layer (a different text starts a
31
+ * fresh one).
32
+ *
33
+ * @returns the layer after the write.
34
+ */
35
+ write(entryId: string, key: string, total: number, updates: ReadonlyMap<number, string>): ReaderPolishView;
36
+ /** Turn one paragraph back to (or away from) the machine translation. */
37
+ setOff(entryId: string, key: string | undefined, paragraph: number, off: boolean): ReaderPolishView | undefined;
38
+ /** Forget an article's layer. */
39
+ drop(entryId: string): void;
40
+ }
41
+ //# sourceMappingURL=polish.d.ts.map
@@ -0,0 +1,136 @@
1
+ /**
2
+ * The 润色 layer: an agent's paragraph-by-paragraph translation of an
3
+ * article, written back through `reader_translate` and shown in place of the
4
+ * browser's sentence-by-sentence machine translation.
5
+ *
6
+ * Keyed to the article's text as the model read it (the snapshot): a
7
+ * re-transcription changes the text and so drops the layer; renaming a
8
+ * speaker only changes the "[mm:ss] 名字:" prefixes and keeps it.
9
+ *
10
+ * One JSON file per article under `<state>/polish/`, memory-only when the
11
+ * state root cannot be written.
12
+ *
13
+ * @module @khorsheed/dsh-reader/polish
14
+ */
15
+ import { createHash } from 'node:crypto';
16
+ import { mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs';
17
+ import { join } from 'node:path';
18
+ /** The time / speaker prefix of a transcript paragraph in the snapshot. */
19
+ const PREFIX = /^\[\d+(?::\d+){1,2}\]\s*(?:[^:\n]{1,40}:)?/;
20
+ /**
21
+ * What a layer belongs to: the paragraphs' text without their time and
22
+ * speaker prefixes, hashed.
23
+ */
24
+ export function sourceKey(paragraphs) {
25
+ const hash = createHash('sha1');
26
+ hash.update(String(paragraphs.length));
27
+ for (const paragraph of paragraphs)
28
+ hash.update(`\n${paragraph.replace(PREFIX, '')}`);
29
+ return hash.digest('hex').slice(0, 24);
30
+ }
31
+ /**
32
+ * Parse the model's write-back: lines `¶12:译文…` (a line without a ¶
33
+ * continues the paragraph before it).
34
+ *
35
+ * @param text - what the model sent.
36
+ */
37
+ export function parsePolish(text) {
38
+ const out = new Map();
39
+ let current;
40
+ for (const line of text.split(/\r?\n/)) {
41
+ const head = /^\s*¶\s*(\d+)\s*[::]\s*(.*)$/.exec(line);
42
+ if (head !== null) {
43
+ current = Number(head[1]);
44
+ out.set(current, head[2].trim());
45
+ }
46
+ else if (current !== undefined && line.trim() !== '') {
47
+ out.set(current, `${out.get(current) ?? ''}${line.trim()}`);
48
+ }
49
+ }
50
+ for (const [key, value] of out)
51
+ if (value === '')
52
+ out.delete(key);
53
+ return out;
54
+ }
55
+ /** The per-article 润色 layers. */
56
+ export class ReaderPolishStore {
57
+ dir;
58
+ memory = new Map();
59
+ constructor(stateRoot) {
60
+ this.dir = join(stateRoot, 'polish');
61
+ }
62
+ fileOf(entryId) {
63
+ return join(this.dir, `${createHash('sha1').update(entryId).digest('hex').slice(0, 32)}.json`);
64
+ }
65
+ load(entryId) {
66
+ const cached = this.memory.get(entryId);
67
+ if (cached !== undefined)
68
+ return cached;
69
+ try {
70
+ const parsed = JSON.parse(readFileSync(this.fileOf(entryId), 'utf8'));
71
+ if (parsed.entryId !== entryId)
72
+ return undefined;
73
+ this.memory.set(entryId, parsed);
74
+ return parsed;
75
+ }
76
+ catch {
77
+ return undefined;
78
+ }
79
+ }
80
+ save(file) {
81
+ this.memory.set(file.entryId, file);
82
+ try {
83
+ mkdirSync(this.dir, { recursive: true });
84
+ const target = this.fileOf(file.entryId);
85
+ writeFileSync(`${target}.tmp`, JSON.stringify(file));
86
+ renameSync(`${target}.tmp`, target);
87
+ }
88
+ catch {
89
+ // Memory-only: the layer lasts this process.
90
+ }
91
+ }
92
+ /**
93
+ * An article's layer, when it belongs to the text now captured.
94
+ *
95
+ * @param entryId - the article.
96
+ * @param key - the current text's {@link sourceKey}.
97
+ */
98
+ view(entryId, key) {
99
+ const file = this.load(entryId);
100
+ if (file === undefined || key === undefined || file.sourceKey !== key)
101
+ return undefined;
102
+ const done = Object.keys(file.paragraphs).length;
103
+ return { total: file.total, done, paragraphs: { ...file.paragraphs }, off: [...file.off], updatedAt: file.updatedAt, complete: done >= file.total };
104
+ }
105
+ /**
106
+ * Merge the model's translations into the layer (a different text starts a
107
+ * fresh one).
108
+ *
109
+ * @returns the layer after the write.
110
+ */
111
+ write(entryId, key, total, updates) {
112
+ const before = this.load(entryId);
113
+ const fresh = before === undefined || before.sourceKey !== key;
114
+ const paragraphs = fresh ? {} : { ...before.paragraphs };
115
+ for (const [index, value] of updates)
116
+ if (index >= 1 && index <= total)
117
+ paragraphs[String(index)] = value;
118
+ const file = { entryId, sourceKey: key, total, paragraphs, off: fresh ? [] : before.off, updatedAt: new Date().toISOString() };
119
+ this.save(file);
120
+ return this.view(entryId, key);
121
+ }
122
+ /** Turn one paragraph back to (or away from) the machine translation. */
123
+ setOff(entryId, key, paragraph, off) {
124
+ const file = this.load(entryId);
125
+ if (file === undefined || key === undefined || file.sourceKey !== key)
126
+ return undefined;
127
+ const rest = file.off.filter(item => item !== paragraph);
128
+ this.save({ ...file, off: off ? [...rest, paragraph] : rest });
129
+ return this.view(entryId, key);
130
+ }
131
+ /** Forget an article's layer. */
132
+ drop(entryId) {
133
+ this.memory.delete(entryId);
134
+ rmSync(this.fileOf(entryId), { force: true });
135
+ }
136
+ }
@@ -11,7 +11,8 @@
11
11
  */
12
12
  import type { Context } from '@deepseek-ai/cordis';
13
13
  import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
14
- import type { ReaderAddFailure, ReaderAddOutcome, ReaderAddRefusal, ReaderAnnotationOutcome, ReaderBackfillCandidate, ReaderEntryBodyView, ReaderEntryFetchState, ReaderBody, ReaderCapabilities, ReaderEntryTranslationView, ReaderMutationOutcome, ReaderRecentEntry, ReaderRefreshResult, ReaderSentenceLearn, ReaderSourceSummary, ReaderStorageStats, ReaderTag } from './types.ts';
14
+ import type { LocalTranscriptStatus, MediaCardStates, ReaderEntryIdentity, ReaderPolishView, ReaderEntryNotes, ReaderMedia, ReaderNote, ReaderNoteInput, ReaderNoteOutcome } from './types.ts';
15
+ import type { ReaderAddFailure, ReaderAddOutcome, ReaderAddRefusal, ReaderAnnotationOutcome, ReaderBackfillCandidate, ReaderEntryBodyView, ReaderImageResult, ReaderEntryFetchState, ReaderBody, ReaderCapabilities, ReaderEntryTranslationView, ReaderMutationOutcome, ReaderRecentEntry, ReaderRefreshResult, ReaderSentenceLearn, ReaderSourceSummary, ReaderStorageStats, ReaderTag } from './types.ts';
15
16
  declare module '@deepseek-ai/cordis' {
16
17
  interface Context {
17
18
  readerRemote: ReaderRemoteService;
@@ -26,6 +27,8 @@ export declare class ReaderRemoteService extends TypertRemoteService<ReaderRemot
26
27
  constructor(ctx: Context, _config?: ReaderRemoteConfig);
27
28
  /** The service core this face delegates to. */
28
29
  private get core();
30
+ /** The notes store this face delegates to. */
31
+ private get notes();
29
32
  /** Capability handshake: what the browser may rely on in this composition. */
30
33
  capabilities(): Promise<ReaderCapabilities>;
31
34
  /** The configured sources, without payloads. */
@@ -80,6 +83,14 @@ export declare class ReaderRemoteService extends TypertRemoteService<ReaderRemot
80
83
  truncated?: boolean;
81
84
  error?: string;
82
85
  }>;
86
+ /**
87
+ * Fetch one image the browser could not load cross-origin (CORP /
88
+ * hotlink-protected), so the pane can re-point the failed `<img>` at the
89
+ * bytes. Called per failed image, never for a healthy one.
90
+ */
91
+ fetchImage(request: {
92
+ url: string;
93
+ }): Promise<ReaderImageResult>;
83
94
  /** Cache the markup the browser extracted for one entry. */
84
95
  storeEntryBody(request: {
85
96
  entryId: string;
@@ -219,6 +230,121 @@ export declare class ReaderRemoteService extends TypertRemoteService<ReaderRemot
219
230
  label: string;
220
231
  text: string;
221
232
  }): Promise<'ok' | 'unavailable'>;
233
+ /** One article's notes and the conversations that discussed it. */
234
+ entryNotes(request: {
235
+ entryId: string;
236
+ }): Promise<{
237
+ entry?: ReaderEntryNotes;
238
+ }>;
239
+ /** How many notes each article carries. */
240
+ noteCounts(): Promise<{
241
+ counts: Record<string, number>;
242
+ }>;
243
+ /** Keep one excerpt (and its comment). */
244
+ addNote(request: ReaderNoteInput): Promise<ReaderNote | 'empty' | 'full'>;
245
+ /** Change or clear one note's comment. */
246
+ updateNote(request: {
247
+ entryId: string;
248
+ noteId: string;
249
+ comment: string;
250
+ }): Promise<ReaderNoteOutcome>;
251
+ /** Delete one note. */
252
+ deleteNote(request: {
253
+ entryId: string;
254
+ noteId: string;
255
+ }): Promise<ReaderNoteOutcome>;
256
+ /** Remember that a conversation discussed this article. */
257
+ recordDiscussion(request: ReaderEntryIdentity & {
258
+ sessionId: string;
259
+ sessionTitle?: string;
260
+ }): Promise<'ok' | 'empty'>;
261
+ /** Add the reader's own line under a note. */
262
+ addReply(request: {
263
+ entryId: string;
264
+ noteId: string;
265
+ text: string;
266
+ }): Promise<ReaderNoteOutcome>;
267
+ /** Rewrite (or, with empty text, remove) one line under a note. */
268
+ editReply(request: {
269
+ entryId: string;
270
+ noteId: string;
271
+ index: number;
272
+ text: string;
273
+ }): Promise<ReaderNoteOutcome>;
274
+ /** Remember that a note or a discussion note became a canvas card. */
275
+ markSynced(request: {
276
+ entryId: string;
277
+ noteId?: string;
278
+ discussionId?: string;
279
+ canvasId: string;
280
+ cardId: string;
281
+ canvasTitle: string;
282
+ }): Promise<ReaderNoteOutcome>;
283
+ /** Delete one discussion note. */
284
+ deleteDiscussion(request: {
285
+ entryId: string;
286
+ discussionId: string;
287
+ }): Promise<ReaderNoteOutcome>;
288
+ /** A video entry's transcript from its platform captions (stored; `none` when it has none). */
289
+ mediaTranscript(request: {
290
+ entryId: string;
291
+ url: string;
292
+ }): Promise<{
293
+ entryId: string;
294
+ html?: string;
295
+ captions: 'platform' | 'none' | 'failed';
296
+ language?: string;
297
+ error?: string;
298
+ }>;
299
+ /**
300
+ * Start (or rejoin) local transcription of an entry without captions.
301
+ * Answers `unavailable` without the transcription plugin and `needs-models`
302
+ * until the first model download is confirmed.
303
+ */
304
+ startLocalTranscript(request: {
305
+ entryId: string;
306
+ url: string;
307
+ media: ReaderMedia;
308
+ title?: string;
309
+ confirmModels?: boolean;
310
+ }): Promise<LocalTranscriptStatus>;
311
+ /** Where an entry's local transcription stands, with the transcript so far. */
312
+ localTranscript(request: {
313
+ entryId: string;
314
+ }): Promise<LocalTranscriptStatus>;
315
+ /** The reader's names for a transcript's speakers, by index. */
316
+ speakerNames(request: {
317
+ entryId: string;
318
+ }): Promise<Record<string, string>>;
319
+ /** Name one speaker of a transcript (empty: back to 说话人 A…); answers all the names. */
320
+ nameSpeaker(request: {
321
+ entryId: string;
322
+ speaker: number;
323
+ name: string;
324
+ }): Promise<Record<string, string>>;
325
+ /** The wall's video / audio cards: what each one's transcript is (captions, local, transcribing…). */
326
+ mediaStates(request: {
327
+ entryIds: string[];
328
+ }): Promise<MediaCardStates>;
329
+ /** Leave (withdraws a queued job) or, with `force`, stop an entry's local transcription. */
330
+ cancelLocalTranscript(request: {
331
+ entryId: string;
332
+ force: boolean;
333
+ }): Promise<LocalTranscriptStatus>;
334
+ /** The article's 润色 layer (the agent's translation), when there is one for its current text. */
335
+ polish(request: {
336
+ entryId: string;
337
+ }): Promise<ReaderPolishView | null>;
338
+ /** Show one paragraph's machine translation instead of the 润色 (or back). */
339
+ setPolishOff(request: {
340
+ entryId: string;
341
+ paragraph: number;
342
+ off: boolean;
343
+ }): Promise<ReaderPolishView | null>;
344
+ /** Hand the host the article's original text, block by block, for the model to read. */
345
+ snapshotEntry(request: ReaderEntryIdentity & {
346
+ paragraphs: string[];
347
+ }): Promise<'ok' | 'empty'>;
222
348
  }
223
349
  export default ReaderRemoteService;
224
350
  //# sourceMappingURL=remote.d.ts.map
@@ -46,6 +46,7 @@ let ReaderRemoteService = (() => {
46
46
  let _getBodies_decorators;
47
47
  let _getEntryBody_decorators;
48
48
  let _fetchEntryBody_decorators;
49
+ let _fetchImage_decorators;
49
50
  let _storeEntryBody_decorators;
50
51
  let _entryFetchStates_decorators;
51
52
  let _getRawBody_decorators;
@@ -68,6 +69,26 @@ let ReaderRemoteService = (() => {
68
69
  let _listRecent_decorators;
69
70
  let _clearRecent_decorators;
70
71
  let _quoteToSideChat_decorators;
72
+ let _entryNotes_decorators;
73
+ let _noteCounts_decorators;
74
+ let _addNote_decorators;
75
+ let _updateNote_decorators;
76
+ let _deleteNote_decorators;
77
+ let _recordDiscussion_decorators;
78
+ let _addReply_decorators;
79
+ let _editReply_decorators;
80
+ let _markSynced_decorators;
81
+ let _deleteDiscussion_decorators;
82
+ let _mediaTranscript_decorators;
83
+ let _startLocalTranscript_decorators;
84
+ let _localTranscript_decorators;
85
+ let _speakerNames_decorators;
86
+ let _nameSpeaker_decorators;
87
+ let _mediaStates_decorators;
88
+ let _cancelLocalTranscript_decorators;
89
+ let _polish_decorators;
90
+ let _setPolishOff_decorators;
91
+ let _snapshotEntry_decorators;
71
92
  return class ReaderRemoteService extends _classSuper {
72
93
  static {
73
94
  const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
@@ -80,6 +101,7 @@ let ReaderRemoteService = (() => {
80
101
  _getBodies_decorators = [Remote('getBodies')];
81
102
  _getEntryBody_decorators = [Remote('getEntryBody')];
82
103
  _fetchEntryBody_decorators = [Remote('fetchEntryBody')];
104
+ _fetchImage_decorators = [Remote('fetchImage')];
83
105
  _storeEntryBody_decorators = [Remote('storeEntryBody')];
84
106
  _entryFetchStates_decorators = [Remote('entryFetchStates')];
85
107
  _getRawBody_decorators = [Remote('getRawBody')];
@@ -102,6 +124,26 @@ let ReaderRemoteService = (() => {
102
124
  _listRecent_decorators = [Remote('listRecent')];
103
125
  _clearRecent_decorators = [Remote('clearRecent')];
104
126
  _quoteToSideChat_decorators = [Remote('quoteToSideChat')];
127
+ _entryNotes_decorators = [Remote('entryNotes')];
128
+ _noteCounts_decorators = [Remote('noteCounts')];
129
+ _addNote_decorators = [Remote('addNote')];
130
+ _updateNote_decorators = [Remote('updateNote')];
131
+ _deleteNote_decorators = [Remote('deleteNote')];
132
+ _recordDiscussion_decorators = [Remote('recordDiscussion')];
133
+ _addReply_decorators = [Remote('addReply')];
134
+ _editReply_decorators = [Remote('editReply')];
135
+ _markSynced_decorators = [Remote('markSynced')];
136
+ _deleteDiscussion_decorators = [Remote('deleteDiscussion')];
137
+ _mediaTranscript_decorators = [Remote('mediaTranscript')];
138
+ _startLocalTranscript_decorators = [Remote('startLocalTranscript')];
139
+ _localTranscript_decorators = [Remote('localTranscript')];
140
+ _speakerNames_decorators = [Remote('speakerNames')];
141
+ _nameSpeaker_decorators = [Remote('nameSpeaker')];
142
+ _mediaStates_decorators = [Remote('mediaStates')];
143
+ _cancelLocalTranscript_decorators = [Remote('cancelLocalTranscript')];
144
+ _polish_decorators = [Remote('polish')];
145
+ _setPolishOff_decorators = [Remote('setPolishOff')];
146
+ _snapshotEntry_decorators = [Remote('snapshotEntry')];
105
147
  __esDecorate(this, null, _capabilities_decorators, { kind: "method", name: "capabilities", static: false, private: false, access: { has: obj => "capabilities" in obj, get: obj => obj.capabilities }, metadata: _metadata }, null, _instanceExtraInitializers);
106
148
  __esDecorate(this, null, _listSources_decorators, { kind: "method", name: "listSources", static: false, private: false, access: { has: obj => "listSources" in obj, get: obj => obj.listSources }, metadata: _metadata }, null, _instanceExtraInitializers);
107
149
  __esDecorate(this, null, _addSource_decorators, { kind: "method", name: "addSource", static: false, private: false, access: { has: obj => "addSource" in obj, get: obj => obj.addSource }, metadata: _metadata }, null, _instanceExtraInitializers);
@@ -111,6 +153,7 @@ let ReaderRemoteService = (() => {
111
153
  __esDecorate(this, null, _getBodies_decorators, { kind: "method", name: "getBodies", static: false, private: false, access: { has: obj => "getBodies" in obj, get: obj => obj.getBodies }, metadata: _metadata }, null, _instanceExtraInitializers);
112
154
  __esDecorate(this, null, _getEntryBody_decorators, { kind: "method", name: "getEntryBody", static: false, private: false, access: { has: obj => "getEntryBody" in obj, get: obj => obj.getEntryBody }, metadata: _metadata }, null, _instanceExtraInitializers);
113
155
  __esDecorate(this, null, _fetchEntryBody_decorators, { kind: "method", name: "fetchEntryBody", static: false, private: false, access: { has: obj => "fetchEntryBody" in obj, get: obj => obj.fetchEntryBody }, metadata: _metadata }, null, _instanceExtraInitializers);
156
+ __esDecorate(this, null, _fetchImage_decorators, { kind: "method", name: "fetchImage", static: false, private: false, access: { has: obj => "fetchImage" in obj, get: obj => obj.fetchImage }, metadata: _metadata }, null, _instanceExtraInitializers);
114
157
  __esDecorate(this, null, _storeEntryBody_decorators, { kind: "method", name: "storeEntryBody", static: false, private: false, access: { has: obj => "storeEntryBody" in obj, get: obj => obj.storeEntryBody }, metadata: _metadata }, null, _instanceExtraInitializers);
115
158
  __esDecorate(this, null, _entryFetchStates_decorators, { kind: "method", name: "entryFetchStates", static: false, private: false, access: { has: obj => "entryFetchStates" in obj, get: obj => obj.entryFetchStates }, metadata: _metadata }, null, _instanceExtraInitializers);
116
159
  __esDecorate(this, null, _getRawBody_decorators, { kind: "method", name: "getRawBody", static: false, private: false, access: { has: obj => "getRawBody" in obj, get: obj => obj.getRawBody }, metadata: _metadata }, null, _instanceExtraInitializers);
@@ -133,9 +176,29 @@ let ReaderRemoteService = (() => {
133
176
  __esDecorate(this, null, _listRecent_decorators, { kind: "method", name: "listRecent", static: false, private: false, access: { has: obj => "listRecent" in obj, get: obj => obj.listRecent }, metadata: _metadata }, null, _instanceExtraInitializers);
134
177
  __esDecorate(this, null, _clearRecent_decorators, { kind: "method", name: "clearRecent", static: false, private: false, access: { has: obj => "clearRecent" in obj, get: obj => obj.clearRecent }, metadata: _metadata }, null, _instanceExtraInitializers);
135
178
  __esDecorate(this, null, _quoteToSideChat_decorators, { kind: "method", name: "quoteToSideChat", static: false, private: false, access: { has: obj => "quoteToSideChat" in obj, get: obj => obj.quoteToSideChat }, metadata: _metadata }, null, _instanceExtraInitializers);
179
+ __esDecorate(this, null, _entryNotes_decorators, { kind: "method", name: "entryNotes", static: false, private: false, access: { has: obj => "entryNotes" in obj, get: obj => obj.entryNotes }, metadata: _metadata }, null, _instanceExtraInitializers);
180
+ __esDecorate(this, null, _noteCounts_decorators, { kind: "method", name: "noteCounts", static: false, private: false, access: { has: obj => "noteCounts" in obj, get: obj => obj.noteCounts }, metadata: _metadata }, null, _instanceExtraInitializers);
181
+ __esDecorate(this, null, _addNote_decorators, { kind: "method", name: "addNote", static: false, private: false, access: { has: obj => "addNote" in obj, get: obj => obj.addNote }, metadata: _metadata }, null, _instanceExtraInitializers);
182
+ __esDecorate(this, null, _updateNote_decorators, { kind: "method", name: "updateNote", static: false, private: false, access: { has: obj => "updateNote" in obj, get: obj => obj.updateNote }, metadata: _metadata }, null, _instanceExtraInitializers);
183
+ __esDecorate(this, null, _deleteNote_decorators, { kind: "method", name: "deleteNote", static: false, private: false, access: { has: obj => "deleteNote" in obj, get: obj => obj.deleteNote }, metadata: _metadata }, null, _instanceExtraInitializers);
184
+ __esDecorate(this, null, _recordDiscussion_decorators, { kind: "method", name: "recordDiscussion", static: false, private: false, access: { has: obj => "recordDiscussion" in obj, get: obj => obj.recordDiscussion }, metadata: _metadata }, null, _instanceExtraInitializers);
185
+ __esDecorate(this, null, _addReply_decorators, { kind: "method", name: "addReply", static: false, private: false, access: { has: obj => "addReply" in obj, get: obj => obj.addReply }, metadata: _metadata }, null, _instanceExtraInitializers);
186
+ __esDecorate(this, null, _editReply_decorators, { kind: "method", name: "editReply", static: false, private: false, access: { has: obj => "editReply" in obj, get: obj => obj.editReply }, metadata: _metadata }, null, _instanceExtraInitializers);
187
+ __esDecorate(this, null, _markSynced_decorators, { kind: "method", name: "markSynced", static: false, private: false, access: { has: obj => "markSynced" in obj, get: obj => obj.markSynced }, metadata: _metadata }, null, _instanceExtraInitializers);
188
+ __esDecorate(this, null, _deleteDiscussion_decorators, { kind: "method", name: "deleteDiscussion", static: false, private: false, access: { has: obj => "deleteDiscussion" in obj, get: obj => obj.deleteDiscussion }, metadata: _metadata }, null, _instanceExtraInitializers);
189
+ __esDecorate(this, null, _mediaTranscript_decorators, { kind: "method", name: "mediaTranscript", static: false, private: false, access: { has: obj => "mediaTranscript" in obj, get: obj => obj.mediaTranscript }, metadata: _metadata }, null, _instanceExtraInitializers);
190
+ __esDecorate(this, null, _startLocalTranscript_decorators, { kind: "method", name: "startLocalTranscript", static: false, private: false, access: { has: obj => "startLocalTranscript" in obj, get: obj => obj.startLocalTranscript }, metadata: _metadata }, null, _instanceExtraInitializers);
191
+ __esDecorate(this, null, _localTranscript_decorators, { kind: "method", name: "localTranscript", static: false, private: false, access: { has: obj => "localTranscript" in obj, get: obj => obj.localTranscript }, metadata: _metadata }, null, _instanceExtraInitializers);
192
+ __esDecorate(this, null, _speakerNames_decorators, { kind: "method", name: "speakerNames", static: false, private: false, access: { has: obj => "speakerNames" in obj, get: obj => obj.speakerNames }, metadata: _metadata }, null, _instanceExtraInitializers);
193
+ __esDecorate(this, null, _nameSpeaker_decorators, { kind: "method", name: "nameSpeaker", static: false, private: false, access: { has: obj => "nameSpeaker" in obj, get: obj => obj.nameSpeaker }, metadata: _metadata }, null, _instanceExtraInitializers);
194
+ __esDecorate(this, null, _mediaStates_decorators, { kind: "method", name: "mediaStates", static: false, private: false, access: { has: obj => "mediaStates" in obj, get: obj => obj.mediaStates }, metadata: _metadata }, null, _instanceExtraInitializers);
195
+ __esDecorate(this, null, _cancelLocalTranscript_decorators, { kind: "method", name: "cancelLocalTranscript", static: false, private: false, access: { has: obj => "cancelLocalTranscript" in obj, get: obj => obj.cancelLocalTranscript }, metadata: _metadata }, null, _instanceExtraInitializers);
196
+ __esDecorate(this, null, _polish_decorators, { kind: "method", name: "polish", static: false, private: false, access: { has: obj => "polish" in obj, get: obj => obj.polish }, metadata: _metadata }, null, _instanceExtraInitializers);
197
+ __esDecorate(this, null, _setPolishOff_decorators, { kind: "method", name: "setPolishOff", static: false, private: false, access: { has: obj => "setPolishOff" in obj, get: obj => obj.setPolishOff }, metadata: _metadata }, null, _instanceExtraInitializers);
198
+ __esDecorate(this, null, _snapshotEntry_decorators, { kind: "method", name: "snapshotEntry", static: false, private: false, access: { has: obj => "snapshotEntry" in obj, get: obj => obj.snapshotEntry }, metadata: _metadata }, null, _instanceExtraInitializers);
136
199
  if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
137
200
  }
138
- static inject = ['reader'];
201
+ static inject = ['reader', 'readerNotes'];
139
202
  constructor(ctx, _config = {}) {
140
203
  super(ctx, 'readerRemote', { namespace: 'reader' });
141
204
  __runInitializers(this, _instanceExtraInitializers);
@@ -144,6 +207,10 @@ let ReaderRemoteService = (() => {
144
207
  get core() {
145
208
  return this.ctx.reader;
146
209
  }
210
+ /** The notes store this face delegates to. */
211
+ get notes() {
212
+ return this.ctx.readerNotes;
213
+ }
147
214
  /** Capability handshake: what the browser may rely on in this composition. */
148
215
  capabilities() {
149
216
  return this.core.capabilities();
@@ -181,6 +248,14 @@ let ReaderRemoteService = (() => {
181
248
  fetchEntryBody(request) {
182
249
  return this.core.fetchEntryBody(request);
183
250
  }
251
+ /**
252
+ * Fetch one image the browser could not load cross-origin (CORP /
253
+ * hotlink-protected), so the pane can re-point the failed `<img>` at the
254
+ * bytes. Called per failed image, never for a healthy one.
255
+ */
256
+ fetchImage(request) {
257
+ return this.core.fetchImage(request);
258
+ }
184
259
  /** Cache the markup the browser extracted for one entry. */
185
260
  storeEntryBody(request) {
186
261
  return this.core.storeEntryBody(request);
@@ -269,6 +344,92 @@ let ReaderRemoteService = (() => {
269
344
  quoteToSideChat(request) {
270
345
  return this.core.quoteToSideChat(request);
271
346
  }
347
+ /* ------------------------------------------------------------------ notes */
348
+ /** One article's notes and the conversations that discussed it. */
349
+ async entryNotes(request) {
350
+ const entry = this.notes.entry(request.entryId);
351
+ return entry === undefined ? {} : { entry };
352
+ }
353
+ /** How many notes each article carries. */
354
+ async noteCounts() {
355
+ return { counts: this.notes.counts() };
356
+ }
357
+ /** Keep one excerpt (and its comment). */
358
+ addNote(request) {
359
+ return this.notes.addNote(request);
360
+ }
361
+ /** Change or clear one note's comment. */
362
+ updateNote(request) {
363
+ return this.notes.updateNote(request);
364
+ }
365
+ /** Delete one note. */
366
+ deleteNote(request) {
367
+ return this.notes.deleteNote(request);
368
+ }
369
+ /** Remember that a conversation discussed this article. */
370
+ recordDiscussion(request) {
371
+ return this.notes.recordSession(request);
372
+ }
373
+ /** Add the reader's own line under a note. */
374
+ addReply(request) {
375
+ return this.notes.addReply({ ...request, by: 'user' });
376
+ }
377
+ /** Rewrite (or, with empty text, remove) one line under a note. */
378
+ editReply(request) {
379
+ return this.notes.editReply(request);
380
+ }
381
+ /** Remember that a note or a discussion note became a canvas card. */
382
+ markSynced(request) {
383
+ return this.notes.markSynced(request);
384
+ }
385
+ /** Delete one discussion note. */
386
+ deleteDiscussion(request) {
387
+ return this.notes.deleteDiscussion(request);
388
+ }
389
+ /** A video entry's transcript from its platform captions (stored; `none` when it has none). */
390
+ mediaTranscript(request) {
391
+ return this.core.mediaTranscript(request);
392
+ }
393
+ /**
394
+ * Start (or rejoin) local transcription of an entry without captions.
395
+ * Answers `unavailable` without the transcription plugin and `needs-models`
396
+ * until the first model download is confirmed.
397
+ */
398
+ startLocalTranscript(request) {
399
+ return this.core.local.start(request);
400
+ }
401
+ /** Where an entry's local transcription stands, with the transcript so far. */
402
+ localTranscript(request) {
403
+ return Promise.resolve(this.core.local.status(request.entryId));
404
+ }
405
+ /** The reader's names for a transcript's speakers, by index. */
406
+ speakerNames(request) {
407
+ return Promise.resolve(this.core.speakerNames(request));
408
+ }
409
+ /** Name one speaker of a transcript (empty: back to 说话人 A…); answers all the names. */
410
+ nameSpeaker(request) {
411
+ return Promise.resolve(this.core.nameSpeaker(request));
412
+ }
413
+ /** The wall's video / audio cards: what each one's transcript is (captions, local, transcribing…). */
414
+ mediaStates(request) {
415
+ return Promise.resolve(this.core.mediaStates(request));
416
+ }
417
+ /** Leave (withdraws a queued job) or, with `force`, stop an entry's local transcription. */
418
+ cancelLocalTranscript(request) {
419
+ return Promise.resolve(this.core.local.cancel(request.entryId, request.force));
420
+ }
421
+ /** The article's 润色 layer (the agent's translation), when there is one for its current text. */
422
+ polish(request) {
423
+ return Promise.resolve(this.notes.polishView(request.entryId) ?? null);
424
+ }
425
+ /** Show one paragraph's machine translation instead of the 润色 (or back). */
426
+ setPolishOff(request) {
427
+ return Promise.resolve(this.notes.setPolishOff(request.entryId, request.paragraph, request.off) ?? null);
428
+ }
429
+ /** Hand the host the article's original text, block by block, for the model to read. */
430
+ snapshotEntry(request) {
431
+ return this.notes.snapshot(request);
432
+ }
272
433
  };
273
434
  })();
274
435
  export { ReaderRemoteService };