@nbtca/prompt 1.4.2 → 1.5.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 (71) hide show
  1. package/README.md +27 -58
  2. package/SECURITY.md +16 -45
  3. package/dist/app/app.js +167 -64
  4. package/dist/app/chrome.js +67 -50
  5. package/dist/app/fields/list-field.js +12 -25
  6. package/dist/app/fields/text-field.js +3 -8
  7. package/dist/app/frame.js +16 -23
  8. package/dist/app/keys.js +110 -2
  9. package/dist/app/views/docs-render.js +34 -26
  10. package/dist/app/views/docs.js +280 -68
  11. package/dist/app/views/events-render.js +21 -27
  12. package/dist/app/views/events.js +57 -33
  13. package/dist/app/views/home.js +67 -47
  14. package/dist/app/views/schedule-grid-cursor.js +9 -18
  15. package/dist/app/views/schedule-render.js +51 -74
  16. package/dist/app/views/schedule.js +246 -101
  17. package/dist/app/views/settings-render.js +8 -19
  18. package/dist/app/views/settings.js +92 -17
  19. package/dist/auth/cookie-transport.js +31 -32
  20. package/dist/auth/errors.js +3 -1
  21. package/dist/auth/nbt-auth.js +42 -25
  22. package/dist/auth/session-store.js +17 -9
  23. package/dist/cli.js +570 -0
  24. package/dist/config/data.js +9 -11
  25. package/dist/config/preferences.js +21 -7
  26. package/dist/core/calendar-day.js +37 -0
  27. package/dist/core/canvas.js +1 -0
  28. package/dist/core/capabilities.js +6 -3
  29. package/dist/core/components/confirm.js +9 -8
  30. package/dist/core/components/menu.js +64 -38
  31. package/dist/core/components/messages.js +12 -4
  32. package/dist/core/components/painter.js +3 -1
  33. package/dist/core/components/spinner.js +34 -7
  34. package/dist/core/components/text-input.js +24 -18
  35. package/dist/core/icons.js +2 -2
  36. package/dist/core/logo.js +23 -5
  37. package/dist/core/motion.js +25 -19
  38. package/dist/core/text.js +186 -69
  39. package/dist/core/theme.js +0 -28
  40. package/dist/core/transitions.js +2 -2
  41. package/dist/core/ui.js +15 -13
  42. package/dist/core/vim-keys.js +156 -19
  43. package/dist/features/about.js +23 -0
  44. package/dist/features/calendar-heatmap.js +16 -40
  45. package/dist/features/calendar-query.js +1 -2
  46. package/dist/features/calendar-store.js +27 -0
  47. package/dist/features/calendar.js +66 -190
  48. package/dist/features/docs-client.js +225 -0
  49. package/dist/features/docs.js +615 -298
  50. package/dist/features/links.js +44 -29
  51. package/dist/features/schedule-render.js +65 -101
  52. package/dist/features/schedule-store.js +51 -9
  53. package/dist/features/schedule-view.js +46 -213
  54. package/dist/features/status.js +117 -60
  55. package/dist/features/student-timetable.js +74 -97
  56. package/dist/features/theme.js +9 -5
  57. package/dist/features/timetable-sanitize.js +40 -0
  58. package/dist/features/update.js +12 -29
  59. package/dist/i18n/index.js +83 -19
  60. package/dist/i18n/locales/en.json +8 -3
  61. package/dist/i18n/locales/zh.json +8 -3
  62. package/dist/index.js +6 -474
  63. package/dist/logo/ca-dotmatrix.txt +16 -18
  64. package/dist/main.js +7 -48
  65. package/package.json +28 -18
  66. package/bin/nbtca-welcome.js +0 -2
  67. package/dist/core/components/screen.js +0 -18
  68. package/dist/core/menu.js +0 -68
  69. package/dist/features/schedule-query.js +0 -47
  70. package/dist/features/settings.js +0 -127
  71. package/dist/logo/ca-logo.png +0 -0
@@ -0,0 +1,225 @@
1
+ import { AsyncLocalStorage } from 'node:async_hooks';
2
+ import { createDocsClient } from '@nbtca/docs';
3
+ const contextKey = Symbol.for('@nbtca/prompt/docs-fetch-context/v2');
4
+ const globalWithContext = globalThis;
5
+ function abortError(signal) {
6
+ return signal.reason instanceof Error ? signal.reason : new DOMException('Aborted', 'AbortError');
7
+ }
8
+ function raceWithSignal(request, signal) {
9
+ if (!signal)
10
+ return request;
11
+ if (signal.aborted)
12
+ return Promise.reject(abortError(signal));
13
+ return new Promise((resolve, reject) => {
14
+ const finish = (result) => {
15
+ signal.removeEventListener('abort', onAbort);
16
+ result();
17
+ };
18
+ const onAbort = () => {
19
+ finish(() => {
20
+ reject(abortError(signal));
21
+ });
22
+ };
23
+ signal.addEventListener('abort', onAbort, { once: true });
24
+ void request.then((value) => {
25
+ finish(() => {
26
+ resolve(value);
27
+ });
28
+ }, (error) => {
29
+ finish(() => {
30
+ reject(error instanceof Error ? error : new Error(String(error)));
31
+ });
32
+ });
33
+ });
34
+ }
35
+ function createDocsFetchContext() {
36
+ const installed = globalWithContext[contextKey];
37
+ if (installed)
38
+ return installed;
39
+ const nativeFetch = globalThis.fetch;
40
+ const storage = new AsyncLocalStorage();
41
+ let delegate = nativeFetch;
42
+ let fallbackDispatching = false;
43
+ const contextualFetch = (input, init) => {
44
+ const forward = (delegate, options) => options ? delegate(input, options) : delegate(input);
45
+ const store = storage.getStore();
46
+ if (!store) {
47
+ if (fallbackDispatching)
48
+ return forward(nativeFetch, init);
49
+ fallbackDispatching = true;
50
+ try {
51
+ return forward(delegate, init);
52
+ }
53
+ finally {
54
+ fallbackDispatching = false;
55
+ }
56
+ }
57
+ if (store.dispatching)
58
+ return forward(nativeFetch, init);
59
+ if (store.signal?.aborted)
60
+ return Promise.reject(abortError(store.signal));
61
+ const requestSignal = init?.signal;
62
+ const signal = store.signal
63
+ ? requestSignal
64
+ ? AbortSignal.any([store.signal, requestSignal])
65
+ : store.signal
66
+ : requestSignal;
67
+ store.dispatching = true;
68
+ try {
69
+ return raceWithSignal(forward(store.delegate, signal ? { ...init, signal } : init), signal);
70
+ }
71
+ finally {
72
+ store.dispatching = false;
73
+ }
74
+ };
75
+ const getFetch = () => (storage.getStore() ? contextualFetch : delegate);
76
+ const setFetch = (value) => {
77
+ delegate = value;
78
+ };
79
+ const context = {
80
+ active: 0,
81
+ contextualFetch,
82
+ get delegate() {
83
+ return delegate;
84
+ },
85
+ set delegate(value) {
86
+ delegate = value;
87
+ },
88
+ getFetch,
89
+ nativeFetch,
90
+ restoreDescriptor: undefined,
91
+ setFetch,
92
+ storage,
93
+ };
94
+ globalWithContext[contextKey] = context;
95
+ return context;
96
+ }
97
+ function beginDocsFetch() {
98
+ const context = createDocsFetchContext();
99
+ const descriptor = Object.getOwnPropertyDescriptor(globalThis, 'fetch');
100
+ const installedAccessor = descriptor?.get === context.getFetch && descriptor.set === context.setFetch;
101
+ const installedValue = descriptor?.value === context.contextualFetch;
102
+ if (context.active === 0)
103
+ context.restoreDescriptor = descriptor;
104
+ if (!installedAccessor && !installedValue) {
105
+ const observed = globalThis.fetch;
106
+ if (observed !== context.contextualFetch)
107
+ context.delegate = observed;
108
+ if (descriptor?.configurable === false) {
109
+ if (descriptor.writable !== true) {
110
+ return {
111
+ context,
112
+ finish() {
113
+ return undefined;
114
+ },
115
+ };
116
+ }
117
+ globalThis.fetch = context.contextualFetch;
118
+ }
119
+ else {
120
+ Object.defineProperty(globalThis, 'fetch', {
121
+ configurable: true,
122
+ enumerable: descriptor?.enumerable ?? true,
123
+ get: context.getFetch,
124
+ set: context.setFetch,
125
+ });
126
+ }
127
+ }
128
+ context.active += 1;
129
+ let finished = false;
130
+ return {
131
+ context,
132
+ finish() {
133
+ if (finished)
134
+ return;
135
+ finished = true;
136
+ context.active = Math.max(0, context.active - 1);
137
+ if (context.active > 0)
138
+ return;
139
+ const current = Object.getOwnPropertyDescriptor(globalThis, 'fetch');
140
+ if (current?.value === context.contextualFetch && current.writable === true) {
141
+ globalThis.fetch = context.delegate;
142
+ return;
143
+ }
144
+ if (current?.get !== context.getFetch || current.set !== context.setFetch)
145
+ return;
146
+ const restore = context.restoreDescriptor;
147
+ if (restore && ('get' in restore || 'set' in restore)) {
148
+ Object.defineProperty(globalThis, 'fetch', restore);
149
+ }
150
+ else {
151
+ Object.defineProperty(globalThis, 'fetch', {
152
+ configurable: restore?.configurable ?? true,
153
+ enumerable: restore?.enumerable ?? true,
154
+ value: context.delegate,
155
+ writable: restore?.writable ?? true,
156
+ });
157
+ }
158
+ },
159
+ };
160
+ }
161
+ const defaultClient = createDocsClient();
162
+ const clientsBySignal = new WeakMap();
163
+ const clients = new Set([defaultClient]);
164
+ function clientFor(signal) {
165
+ if (!signal)
166
+ return defaultClient;
167
+ const existing = clientsBySignal.get(signal);
168
+ if (existing)
169
+ return existing;
170
+ const client = createDocsClient();
171
+ clientsBySignal.set(signal, client);
172
+ clients.add(client);
173
+ signal.addEventListener('abort', () => {
174
+ client.clear();
175
+ clients.delete(client);
176
+ clientsBySignal.delete(signal);
177
+ }, { once: true });
178
+ return client;
179
+ }
180
+ export function clearDocsClients() {
181
+ for (const client of clients)
182
+ client.clear();
183
+ }
184
+ export function runDocsClientOperation(signal, operation) {
185
+ if (signal?.aborted)
186
+ return Promise.reject(abortError(signal));
187
+ const scope = beginDocsFetch();
188
+ let request;
189
+ try {
190
+ request = scope.context.storage.run({ delegate: scope.context.delegate, dispatching: false, signal }, () => operation(clientFor(signal)));
191
+ }
192
+ catch (error) {
193
+ scope.finish();
194
+ return Promise.reject(error instanceof Error ? error : new Error(String(error)));
195
+ }
196
+ return new Promise((resolve, reject) => {
197
+ let settled = false;
198
+ const settle = (result) => {
199
+ if (settled)
200
+ return;
201
+ settled = true;
202
+ signal?.removeEventListener('abort', onAbort);
203
+ result();
204
+ };
205
+ const onAbort = () => {
206
+ settle(() => {
207
+ reject(signal ? abortError(signal) : new DOMException('Aborted', 'AbortError'));
208
+ });
209
+ };
210
+ signal?.addEventListener('abort', onAbort, { once: true });
211
+ if (signal?.aborted)
212
+ onAbort();
213
+ void request.then((value) => {
214
+ scope.finish();
215
+ settle(() => {
216
+ resolve(value);
217
+ });
218
+ }, (error) => {
219
+ scope.finish();
220
+ settle(() => {
221
+ reject(error instanceof Error ? error : new Error(String(error)));
222
+ });
223
+ });
224
+ });
225
+ }