@fnndsc/salsa 3.5.1 → 3.6.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.
Files changed (73) hide show
  1. package/README.md +3 -3
  2. package/dist/connect/index.d.ts +11 -0
  3. package/dist/connect/index.js +11 -0
  4. package/dist/connect/index.js.map +1 -1
  5. package/dist/dag/feedJoins.js +4 -1
  6. package/dist/dag/feedJoins.js.map +1 -1
  7. package/dist/feeds/index.d.ts +15 -2
  8. package/dist/feeds/index.js.map +1 -1
  9. package/dist/files/index.d.ts +7 -0
  10. package/dist/files/index.js +12 -11
  11. package/dist/files/index.js.map +1 -1
  12. package/dist/files/regular_content.js +11 -3
  13. package/dist/files/regular_content.js.map +1 -1
  14. package/dist/groups/index.d.ts +59 -0
  15. package/dist/groups/index.js +89 -0
  16. package/dist/groups/index.js.map +1 -1
  17. package/dist/groups/membershipRevision.d.ts +19 -0
  18. package/dist/groups/membershipRevision.js +29 -0
  19. package/dist/groups/membershipRevision.js.map +1 -0
  20. package/dist/index.d.ts +3 -1
  21. package/dist/index.js +5 -1
  22. package/dist/index.js.map +1 -1
  23. package/dist/jobs/jobOps.js +45 -2
  24. package/dist/jobs/jobOps.js.map +1 -1
  25. package/dist/pipelines/index.d.ts +28 -5
  26. package/dist/pipelines/index.js +110 -48
  27. package/dist/pipelines/index.js.map +1 -1
  28. package/dist/pipelines/invocation.d.ts +80 -0
  29. package/dist/pipelines/invocation.js +290 -0
  30. package/dist/pipelines/invocation.js.map +1 -0
  31. package/dist/pipelines/manifest.d.ts +102 -0
  32. package/dist/pipelines/manifest.js +204 -0
  33. package/dist/pipelines/manifest.js.map +1 -0
  34. package/dist/plugins/index.d.ts +29 -0
  35. package/dist/plugins/index.js +51 -10
  36. package/dist/plugins/index.js.map +1 -1
  37. package/dist/plugins/internal/plugin_executeNewFeed.d.ts +0 -14
  38. package/dist/plugins/internal/plugin_executeNewFeed.js +3 -3
  39. package/dist/plugins/internal/plugin_executeNewFeed.js.map +1 -1
  40. package/dist/plugins/plugin_register.js +5 -5
  41. package/dist/plugins/plugin_register.js.map +1 -1
  42. package/dist/plugins/store_import.js +1 -1
  43. package/dist/plugins/store_import.js.map +1 -1
  44. package/dist/retrieve/watch.d.ts +114 -0
  45. package/dist/retrieve/watch.js +360 -0
  46. package/dist/retrieve/watch.js.map +1 -0
  47. package/dist/store/index.d.ts +17 -4
  48. package/dist/store/index.js +9 -4
  49. package/dist/store/index.js.map +1 -1
  50. package/dist/users/index.d.ts +36 -0
  51. package/dist/users/index.js +50 -0
  52. package/dist/users/index.js.map +1 -0
  53. package/dist/vfs/dispatcher.d.ts +11 -0
  54. package/dist/vfs/dispatcher.js +37 -6
  55. package/dist/vfs/dispatcher.js.map +1 -1
  56. package/dist/vfs/index.d.ts +1 -0
  57. package/dist/vfs/index.js +3 -0
  58. package/dist/vfs/index.js.map +1 -1
  59. package/dist/vfs/provider.d.ts +13 -0
  60. package/dist/vfs/providers/etc.d.ts +2 -0
  61. package/dist/vfs/providers/etc.js +41 -2
  62. package/dist/vfs/providers/etc.js.map +1 -1
  63. package/dist/vfs/providers/native.js +41 -7
  64. package/dist/vfs/providers/native.js.map +1 -1
  65. package/dist/vfs/providers/pacs.d.ts +13 -1
  66. package/dist/vfs/providers/pacs.js +86 -107
  67. package/dist/vfs/providers/pacs.js.map +1 -1
  68. package/dist/vfs/providers/pacsHelpers.js +9 -5
  69. package/dist/vfs/providers/pacsHelpers.js.map +1 -1
  70. package/dist/vfs/providers/proc.d.ts +34 -1
  71. package/dist/vfs/providers/proc.js +301 -62
  72. package/dist/vfs/providers/proc.js.map +1 -1
  73. package/package.json +11 -8
@@ -0,0 +1,360 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.retrieveTask_make = retrieveTask_make;
7
+ exports.retrieveProgress_classify = retrieveProgress_classify;
8
+ exports.retrieveTasks_skipComplete = retrieveTasks_skipComplete;
9
+ exports.retrieveTasks_fire = retrieveTasks_fire;
10
+ exports.retrieve_fireAndWatch = retrieve_fireAndWatch;
11
+ exports.retrieve_confirmLoop = retrieve_confirmLoop;
12
+ /**
13
+ * @file PACS retrieve engine: fire, watch, confirm.
14
+ *
15
+ * The single implementation of "make DICOM series land in CUBE and know when
16
+ * they have": synthetic query+retrieve firing with bounded concurrency and
17
+ * per-step retry, a LONK WebSocket watch with stall/timeout/no-activity
18
+ * detection, storage-side confirmation across registration lag, and an
19
+ * optional refire loop for unconfirmed series. Both consumers (the `pull`
20
+ * builtin in brasa and the PACS VFS provider's `cp`) previously solved this
21
+ * independently — LONK push versus 5-second polling — with different
22
+ * semantics; this module is the convergence (docs/code-audit-2026-08.adoc,
23
+ * decisions section).
24
+ *
25
+ * The engine is presentation-free: progress is reported through the
26
+ * {@link RetrieveWatchEvents} callbacks and consumers render it however their
27
+ * surface renders (structured sink progress, plain console lines).
28
+ *
29
+ * @module
30
+ */
31
+ const ws_1 = __importDefault(require("ws"));
32
+ const cumin_1 = require("@fnndsc/cumin");
33
+ /** Concurrent retrieve creations; more overloads CUBE and loses retrieves. */
34
+ const FIRE_CONCURRENCY = 4;
35
+ /** Retry attempts for one retrieve creation, with backoff between them. */
36
+ const FIRE_ATTEMPTS = 3;
37
+ const FIRE_BACKOFF_MS = [250, 500];
38
+ const STALL_TIMEOUT_MS = 30_000;
39
+ const NO_ACTIVITY_TIMEOUT_MS = 15_000;
40
+ const SERIES_TIMEOUT_MS = 5 * 60 * 1_000;
41
+ const CHECKER_INTERVAL_MS = 2_000;
42
+ /**
43
+ * Builds a fresh retrieve task from series identity facts.
44
+ *
45
+ * @param info - Label, UIDs, PACS name, and expected file count.
46
+ * @returns A pending task ready for {@link retrieve_fireAndWatch}.
47
+ */
48
+ function retrieveTask_make(info) {
49
+ return {
50
+ ...info,
51
+ syntheticQueryId: null,
52
+ retrieveId: null,
53
+ status: 'pending',
54
+ actualFiles: 0,
55
+ lastProgressFiles: 0,
56
+ lastProgressTime: Date.now(),
57
+ startTime: 0,
58
+ lonkConfirmed: false,
59
+ cubePathDir: null,
60
+ };
61
+ }
62
+ /**
63
+ * Classifies a task's state for progress reporting.
64
+ *
65
+ * @param task - The task to classify.
66
+ * @returns The progress status consumers render.
67
+ */
68
+ function retrieveProgress_classify(task) {
69
+ if (task.status === 'pulled')
70
+ return task.lonkConfirmed ? 'done' : 'unconfirmed';
71
+ if (task.status === 'pending' || task.status === 'pulling')
72
+ return 'running';
73
+ if (task.status === 'unfired')
74
+ return 'error';
75
+ return task.status;
76
+ }
77
+ /**
78
+ * Marks tasks whose series are already fully registered in CUBE as pulled,
79
+ * so firing skips them. This is what makes a retrieve idempotent: re-running
80
+ * the same request after a partial failure fetches only the missing series.
81
+ *
82
+ * @param tasks - All tasks; complete ones are mutated to pulled.
83
+ * @returns How many tasks were marked complete and skipped.
84
+ */
85
+ async function retrieveTasks_skipComplete(tasks) {
86
+ let skipped = 0;
87
+ await Promise.all(tasks.map(async (task) => {
88
+ const stateResult = await (0, cumin_1.seriesStorage_resolve)(task.seriesUID);
89
+ if (!stateResult.ok)
90
+ return;
91
+ const state = stateResult.value;
92
+ if (task.expectedFiles > 0 && state.fileCount >= task.expectedFiles && state.folderPath !== null) {
93
+ task.status = 'pulled';
94
+ task.lonkConfirmed = true;
95
+ task.actualFiles = state.fileCount;
96
+ task.cubePathDir = state.folderPath;
97
+ skipped++;
98
+ }
99
+ }));
100
+ return skipped;
101
+ }
102
+ /**
103
+ * Creates a synthetic PACSQuery + PACSRetrieve for a single series, with
104
+ * bounded retry: creation failures during a server brown-out are permanent
105
+ * data loss for the run (nothing ever retrieves), so each series gets a few
106
+ * attempts before it is declared unfired.
107
+ *
108
+ * @param task - The task to fire (mutated: syntheticQueryId, retrieveId, startTime, status).
109
+ * @param pacsserver - Resolved PACS server ID string.
110
+ */
111
+ async function task_fire(task, pacsserver) {
112
+ const fired = await (0, cumin_1.retry_untilValue)(FIRE_ATTEMPTS, FIRE_BACKOFF_MS, async () => {
113
+ const queryData = {
114
+ // CUBE rejects duplicate query titles per user; a timestamp keeps
115
+ // re-pull titles unique.
116
+ title: `pull_${task.seriesUID}_${Date.now().toString(36)}`,
117
+ query: JSON.stringify({
118
+ SeriesInstanceUID: task.seriesUID,
119
+ StudyInstanceUID: task.studyUID,
120
+ }),
121
+ execute: false,
122
+ };
123
+ const queryResult = await (0, cumin_1.pacsQueries_create)(pacsserver, queryData);
124
+ if (!queryResult.ok)
125
+ return null;
126
+ const retrieveResult = await (0, cumin_1.pacsRetrieve_create)(queryResult.value.id);
127
+ if (!retrieveResult.ok)
128
+ return null;
129
+ return { queryId: queryResult.value.id, retrieveId: retrieveResult.value.id };
130
+ });
131
+ if (fired === null) {
132
+ task.status = 'unfired';
133
+ return;
134
+ }
135
+ task.syntheticQueryId = fired.queryId;
136
+ task.retrieveId = fired.retrieveId;
137
+ task.startTime = Date.now();
138
+ }
139
+ /**
140
+ * Fires retrieves with bounded concurrency, so a large study does not
141
+ * stampede CUBE with parallel creations (the overload that loses retrieves
142
+ * in the first place).
143
+ *
144
+ * @param tasks - Tasks to fire.
145
+ * @param pacsserver - Resolved PACS server identifier.
146
+ */
147
+ async function tasks_fireBounded(tasks, pacsserver) {
148
+ let next = 0;
149
+ const worker = async () => {
150
+ while (next < tasks.length) {
151
+ const task = tasks[next++];
152
+ await task_fire(task, pacsserver);
153
+ }
154
+ };
155
+ await Promise.all(Array.from({ length: Math.min(FIRE_CONCURRENCY, tasks.length) }, () => worker()));
156
+ }
157
+ /**
158
+ * Fires retrieves for tasks (bounded, retried) without watching: the
159
+ * fire-and-exit path (`pull --nowait`). Tasks that could not fire are left
160
+ * in the `unfired` state.
161
+ *
162
+ * @param tasks - Tasks to fire.
163
+ * @param pacsserver - Resolved PACS server identifier.
164
+ */
165
+ async function retrieveTasks_fire(tasks, pacsserver) {
166
+ await tasks_fireBounded(tasks, pacsserver);
167
+ }
168
+ /**
169
+ * Constructs a LONK WebSocket URL from a download token response.
170
+ *
171
+ * @param tokenUrl - The download token resource URL.
172
+ * @param token - The actual download token string.
173
+ * @returns WebSocket URL for the LONK endpoint.
174
+ */
175
+ function lonkWsUrl_build(tokenUrl, token) {
176
+ return tokenUrl
177
+ .replace(/^http(s?):\/\//, (_m, s) => `ws${s}://`)
178
+ .replace(/v1\/downloadtokens\/\d+\//, `v1/pacs/ws/?token=${token}`);
179
+ }
180
+ /**
181
+ * Opens a LONK WebSocket, fires retrieves for the tasks, and blocks until
182
+ * every task reaches a terminal state. Mutates each task's status,
183
+ * actualFiles, and lonkConfirmed; reports progress through the events.
184
+ *
185
+ * @param tasks - Tasks to subscribe, fire, and watch.
186
+ * @param pacsserver - Resolved PACS server identifier.
187
+ * @param client - Authenticated ChRIS API client (for the LONK token).
188
+ * @param events - Progress callbacks.
189
+ * @param phase - Phase tag passed through to task events.
190
+ * @returns Number of tasks whose retrieve could not be fired.
191
+ */
192
+ async function retrieve_fireAndWatch(tasks, pacsserver, client, events = {}, phase = 'watching') {
193
+ const emit = (task, status) => {
194
+ events.task?.(task, status ?? retrieveProgress_classify(task), phase);
195
+ };
196
+ const tokenClient = client;
197
+ const downloadToken = await tokenClient.createDownloadToken();
198
+ const tokenStr = String(downloadToken.data.token ?? '');
199
+ const ws = new ws_1.default(lonkWsUrl_build(downloadToken.url, tokenStr));
200
+ await new Promise((openResolve, openReject) => {
201
+ ws.once('open', openResolve);
202
+ ws.once('error', (err) => openReject(err));
203
+ });
204
+ for (const t of tasks) {
205
+ ws.send(JSON.stringify({ SeriesInstanceUID: t.seriesUID, pacs_name: t.pacsName, action: 'subscribe' }));
206
+ }
207
+ await tasks_fireBounded(tasks, pacsserver);
208
+ const fired = tasks.filter((t) => t.status !== 'unfired');
209
+ const firingErrors = tasks.length - fired.length;
210
+ if (fired.length === 0) {
211
+ for (const t of tasks) {
212
+ if (t.status === 'unfired')
213
+ emit(t, 'error');
214
+ }
215
+ ws.close();
216
+ return firingErrors;
217
+ }
218
+ for (const t of tasks) {
219
+ emit(t, t.status === 'unfired' ? 'error' : 'running');
220
+ }
221
+ const taskByUID = new Map(tasks.map((t) => [t.seriesUID, t]));
222
+ await new Promise((resolve) => {
223
+ let resolved = false;
224
+ const done = () => {
225
+ if (resolved)
226
+ return;
227
+ resolved = true;
228
+ clearInterval(checker);
229
+ try {
230
+ ws.close();
231
+ }
232
+ catch { /* best-effort socket cleanup */ }
233
+ resolve();
234
+ };
235
+ const checker = setInterval(() => {
236
+ const now = Date.now();
237
+ let allTerminal = true;
238
+ for (const t of fired) {
239
+ if (t.status === 'pulled' || t.status === 'error' || t.status === 'unfired' || t.status === 'stalled' || t.status === 'timeout') {
240
+ continue;
241
+ }
242
+ allTerminal = false;
243
+ if (t.startTime > 0 && now - t.startTime > SERIES_TIMEOUT_MS) {
244
+ t.status = 'timeout';
245
+ emit(t, 'timeout');
246
+ continue;
247
+ }
248
+ if (t.actualFiles > 0 && now - t.lastProgressTime > STALL_TIMEOUT_MS) {
249
+ t.status = 'stalled';
250
+ emit(t, 'stalled');
251
+ continue;
252
+ }
253
+ if (t.startTime > 0 && t.actualFiles === 0 && now - t.startTime > NO_ACTIVITY_TIMEOUT_MS) {
254
+ t.status = 'pulled';
255
+ t.lonkConfirmed = false;
256
+ emit(t, 'unconfirmed');
257
+ continue;
258
+ }
259
+ }
260
+ if (allTerminal)
261
+ done();
262
+ }, CHECKER_INTERVAL_MS);
263
+ ws.on('message', (data) => {
264
+ try {
265
+ const outer = JSON.parse(data.toString());
266
+ const seriesUID = outer.SeriesInstanceUID;
267
+ const message = outer.message;
268
+ if (!seriesUID || !message)
269
+ return;
270
+ const t = taskByUID.get(seriesUID);
271
+ if (!t)
272
+ return;
273
+ if ('ndicom' in message && typeof message.ndicom === 'number') {
274
+ const n = message.ndicom;
275
+ t.actualFiles = n;
276
+ t.lastProgressFiles = n;
277
+ t.lastProgressTime = Date.now();
278
+ if (t.status === 'pending')
279
+ t.status = 'pulling';
280
+ emit(t, 'running');
281
+ }
282
+ else if ('done' in message && message.done === true) {
283
+ t.status = 'pulled';
284
+ t.lonkConfirmed = true;
285
+ if (t.actualFiles < t.expectedFiles)
286
+ t.actualFiles = t.expectedFiles;
287
+ emit(t, 'done');
288
+ }
289
+ else if ('error' in message && typeof message.error === 'string') {
290
+ t.status = 'error';
291
+ emit(t, 'error');
292
+ }
293
+ }
294
+ catch {
295
+ // Deliberate absorption: a malformed LONK frame carries no correlation
296
+ // to fail; the checker's stall/timeout guards still bound the watch.
297
+ }
298
+ });
299
+ ws.on('error', () => {
300
+ for (const t of fired) {
301
+ if (t.status === 'pending' || t.status === 'pulling') {
302
+ t.status = 'error';
303
+ emit(t, 'error');
304
+ }
305
+ }
306
+ done();
307
+ });
308
+ ws.on('close', () => { done(); });
309
+ });
310
+ return firingErrors;
311
+ }
312
+ /**
313
+ * Confirms unconfirmed series against CUBE storage and refires the rest, up
314
+ * to `retryMax` rounds; series still unconfirmed afterwards are marked
315
+ * errored. This closes the gap between a lost LONK confirmation (cosmetic)
316
+ * and a retrieve that genuinely never delivered (real loss).
317
+ *
318
+ * @param allTasks - All tasks from the initial watch.
319
+ * @param retryMax - Maximum refire rounds.
320
+ * @param pacsserver - The PACS server identifier.
321
+ * @param client - The connected ChRIS client.
322
+ * @param events - Progress callbacks.
323
+ * @returns The number of additional firing errors incurred.
324
+ */
325
+ async function retrieve_confirmLoop(allTasks, retryMax, pacsserver, client, events = {}) {
326
+ let extraFiringErrors = 0;
327
+ let retryCandidates = allTasks.filter((t) => t.status === 'pulled' && !t.lonkConfirmed);
328
+ for (let attempt = 1; attempt <= retryMax && retryCandidates.length > 0; attempt++) {
329
+ await Promise.all(retryCandidates.map(async (t) => {
330
+ const stateResult = await (0, cumin_1.seriesStorage_resolve)(t.seriesUID);
331
+ if (stateResult.ok && stateResult.value.folderPath !== null) {
332
+ t.lonkConfirmed = true;
333
+ t.cubePathDir = stateResult.value.folderPath;
334
+ }
335
+ }));
336
+ retryCandidates = retryCandidates.filter((t) => !t.lonkConfirmed);
337
+ if (retryCandidates.length === 0)
338
+ break;
339
+ events.retryRound?.(attempt, retryMax, retryCandidates.length);
340
+ for (const t of retryCandidates) {
341
+ t.status = 'pending';
342
+ t.actualFiles = 0;
343
+ t.lastProgressFiles = 0;
344
+ t.lastProgressTime = Date.now();
345
+ t.startTime = 0;
346
+ t.lonkConfirmed = false;
347
+ t.syntheticQueryId = null;
348
+ t.retrieveId = null;
349
+ events.task?.(t, 'running', 'retrying');
350
+ }
351
+ extraFiringErrors += await retrieve_fireAndWatch(retryCandidates, pacsserver, client, events, 'retrying');
352
+ retryCandidates = retryCandidates.filter((t) => t.status === 'pulled' && !t.lonkConfirmed);
353
+ }
354
+ for (const t of retryCandidates) {
355
+ t.status = 'error';
356
+ events.task?.(t, 'error', 'retrying');
357
+ }
358
+ return extraFiringErrors;
359
+ }
360
+ //# sourceMappingURL=watch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watch.js","sourceRoot":"","sources":["../../src/retrieve/watch.ts"],"names":[],"mappings":"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"}
@@ -1,15 +1,28 @@
1
+ /**
2
+ * @file Store operations.
3
+ *
4
+ * Logic for interacting with the peer ChRIS store (listing, searching).
5
+ * Failures propagate as Err rather than an empty array, so a store outage is
6
+ * distinguishable from a store with no plugins; the underlying fetch has
7
+ * already pushed its reason onto the error stack.
8
+ *
9
+ * @module
10
+ */
11
+ import { Result } from '@fnndsc/cumin';
1
12
  /**
2
13
  * Lists plugins from the peer store.
3
14
  *
4
15
  * @param storeUrl - Optional URL of the peer store.
5
- * @returns Promise resolving to array of raw plugin objects.
16
+ * @returns Ok with raw plugin objects (possibly empty), or Err when the store
17
+ * fetch failed (reason already on the error stack).
6
18
  */
7
- export declare function store_list(storeUrl?: string): Promise<Record<string, unknown>[]>;
19
+ export declare function store_list(storeUrl?: string): Promise<Result<Record<string, unknown>[]>>;
8
20
  /**
9
21
  * Searches plugins in the peer store.
10
22
  *
11
23
  * @param query - Search query (e.g. plugin name substring).
12
24
  * @param storeUrl - Optional URL of the peer store.
13
- * @returns Promise resolving to array of raw plugin objects.
25
+ * @returns Ok with matching raw plugin objects (possibly empty), or Err when
26
+ * the store fetch failed (reason already on the error stack).
14
27
  */
15
- export declare function store_search(query: string, storeUrl?: string): Promise<Record<string, unknown>[]>;
28
+ export declare function store_search(query: string, storeUrl?: string): Promise<Result<Record<string, unknown>[]>>;
@@ -6,6 +6,9 @@ exports.store_search = store_search;
6
6
  * @file Store operations.
7
7
  *
8
8
  * Logic for interacting with the peer ChRIS store (listing, searching).
9
+ * Failures propagate as Err rather than an empty array, so a store outage is
10
+ * distinguishable from a store with no plugins; the underlying fetch has
11
+ * already pushed its reason onto the error stack.
9
12
  *
10
13
  * @module
11
14
  */
@@ -14,24 +17,26 @@ const cumin_1 = require("@fnndsc/cumin");
14
17
  * Lists plugins from the peer store.
15
18
  *
16
19
  * @param storeUrl - Optional URL of the peer store.
17
- * @returns Promise resolving to array of raw plugin objects.
20
+ * @returns Ok with raw plugin objects (possibly empty), or Err when the store
21
+ * fetch failed (reason already on the error stack).
18
22
  */
19
23
  async function store_list(storeUrl) {
20
24
  const chrisPlugin = new cumin_1.ChRISPlugin();
21
25
  const plugins = await chrisPlugin.plugin_listPeerStore(storeUrl);
22
- return plugins || [];
26
+ return plugins === null ? (0, cumin_1.Err)() : (0, cumin_1.Ok)(plugins);
23
27
  }
24
28
  /**
25
29
  * Searches plugins in the peer store.
26
30
  *
27
31
  * @param query - Search query (e.g. plugin name substring).
28
32
  * @param storeUrl - Optional URL of the peer store.
29
- * @returns Promise resolving to array of raw plugin objects.
33
+ * @returns Ok with matching raw plugin objects (possibly empty), or Err when
34
+ * the store fetch failed (reason already on the error stack).
30
35
  */
31
36
  async function store_search(query, storeUrl) {
32
37
  const chrisPlugin = new cumin_1.ChRISPlugin();
33
38
  // Search by name
34
39
  const plugins = await chrisPlugin.plugin_listPeerStore(storeUrl, { name: query });
35
- return plugins || [];
40
+ return plugins === null ? (0, cumin_1.Err)() : (0, cumin_1.Ok)(plugins);
36
41
  }
37
42
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/store/index.ts"],"names":[],"mappings":";;AAeA,gCAIC;AASD,oCAKC;AAjCD;;;;;;GAMG;AACH,yCAA4C;AAE5C;;;;;GAKG;AACI,KAAK,UAAU,UAAU,CAAC,QAAiB;IAChD,MAAM,WAAW,GAAgB,IAAI,mBAAW,EAAE,CAAC;IACnD,MAAM,OAAO,GAAqC,MAAM,WAAW,CAAC,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IACnG,OAAO,OAAO,IAAI,EAAE,CAAC;AACvB,CAAC;AAED;;;;;;GAMG;AACI,KAAK,UAAU,YAAY,CAAC,KAAa,EAAE,QAAiB;IACjE,MAAM,WAAW,GAAgB,IAAI,mBAAW,EAAE,CAAC;IACnD,iBAAiB;IACjB,MAAM,OAAO,GAAqC,MAAM,WAAW,CAAC,oBAAoB,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACpH,OAAO,OAAO,IAAI,EAAE,CAAC;AACvB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/store/index.ts"],"names":[],"mappings":";;AAmBA,gCAIC;AAUD,oCAKC;AAtCD;;;;;;;;;GASG;AACH,yCAA6D;AAE7D;;;;;;GAMG;AACI,KAAK,UAAU,UAAU,CAAC,QAAiB;IAChD,MAAM,WAAW,GAAgB,IAAI,mBAAW,EAAE,CAAC;IACnD,MAAM,OAAO,GAAqC,MAAM,WAAW,CAAC,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IACnG,OAAO,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,IAAA,WAAG,GAAE,CAAC,CAAC,CAAC,IAAA,UAAE,EAAC,OAAO,CAAC,CAAC;AAChD,CAAC;AAED;;;;;;;GAOG;AACI,KAAK,UAAU,YAAY,CAAC,KAAa,EAAE,QAAiB;IACjE,MAAM,WAAW,GAAgB,IAAI,mBAAW,EAAE,CAAC;IACnD,iBAAiB;IACjB,MAAM,OAAO,GAAqC,MAAM,WAAW,CAAC,oBAAoB,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACpH,OAAO,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,IAAA,WAAG,GAAE,CAAC,CAAC,CAAC,IAAA,UAAE,EAAC,OAAO,CAAC,CAAC;AAChD,CAAC"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * @file CUBE-local account operation facade.
3
+ * @module
4
+ */
5
+ import { type LocalAccount, type LocalAccountAction, type Result } from '@fnndsc/cumin';
6
+ export type { LocalAccount, LocalAccountAction, Result };
7
+ /**
8
+ * Verifies that the current identity may use local-account administration.
9
+ *
10
+ * @returns Success when the active CUBE identity has account-admin access.
11
+ */
12
+ export declare function localAccount_adminAccessEnsure(): Promise<Result<void>>;
13
+ /**
14
+ * Creates one CUBE-local account.
15
+ *
16
+ * @param username - New local username.
17
+ * @param email - Account email address.
18
+ * @param password - Initial local-login password.
19
+ * @returns The created account or an operation error.
20
+ */
21
+ export declare function localAccount_create(username: string, email: string, password: string): Promise<Result<LocalAccount>>;
22
+ /**
23
+ * Finds one CUBE-local account by exact username.
24
+ *
25
+ * @param username - Exact local username.
26
+ * @returns The matching account or an operation error.
27
+ */
28
+ export declare function localAccount_find(username: string): Promise<Result<LocalAccount>>;
29
+ /**
30
+ * Changes the lifecycle state of one CUBE-local account.
31
+ *
32
+ * @param accountID - Stable local-account record identifier.
33
+ * @param action - Lifecycle transition to apply.
34
+ * @returns The updated account or an operation error.
35
+ */
36
+ export declare function localAccount_action(accountID: number, action: LocalAccountAction): Promise<Result<LocalAccount>>;
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.localAccount_adminAccessEnsure = localAccount_adminAccessEnsure;
4
+ exports.localAccount_create = localAccount_create;
5
+ exports.localAccount_find = localAccount_find;
6
+ exports.localAccount_action = localAccount_action;
7
+ /**
8
+ * @file CUBE-local account operation facade.
9
+ * @module
10
+ */
11
+ const cumin_1 = require("@fnndsc/cumin");
12
+ /**
13
+ * Verifies that the current identity may use local-account administration.
14
+ *
15
+ * @returns Success when the active CUBE identity has account-admin access.
16
+ */
17
+ async function localAccount_adminAccessEnsure() {
18
+ return await (0, cumin_1.localAccount_adminAccessEnsure)();
19
+ }
20
+ /**
21
+ * Creates one CUBE-local account.
22
+ *
23
+ * @param username - New local username.
24
+ * @param email - Account email address.
25
+ * @param password - Initial local-login password.
26
+ * @returns The created account or an operation error.
27
+ */
28
+ async function localAccount_create(username, email, password) {
29
+ return await (0, cumin_1.localAccount_create)(username, email, password);
30
+ }
31
+ /**
32
+ * Finds one CUBE-local account by exact username.
33
+ *
34
+ * @param username - Exact local username.
35
+ * @returns The matching account or an operation error.
36
+ */
37
+ async function localAccount_find(username) {
38
+ return await (0, cumin_1.localAccount_find)(username);
39
+ }
40
+ /**
41
+ * Changes the lifecycle state of one CUBE-local account.
42
+ *
43
+ * @param accountID - Stable local-account record identifier.
44
+ * @param action - Lifecycle transition to apply.
45
+ * @returns The updated account or an operation error.
46
+ */
47
+ async function localAccount_action(accountID, action) {
48
+ return await (0, cumin_1.localAccount_action)(accountID, action);
49
+ }
50
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/users/index.ts"],"names":[],"mappings":";;AAqBA,wEAEC;AAUD,kDAIC;AAQD,8CAEC;AASD,kDAIC;AA5DD;;;GAGG;AACH,yCAQuB;AAIvB;;;;GAIG;AACI,KAAK,UAAU,8BAA8B;IAClD,OAAO,MAAM,IAAA,sCAAoC,GAAE,CAAC;AACtD,CAAC;AAED;;;;;;;GAOG;AACI,KAAK,UAAU,mBAAmB,CACvC,QAAgB,EAAE,KAAa,EAAE,QAAgB;IAEjD,OAAO,MAAM,IAAA,2BAAyB,EAAC,QAAQ,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;AACpE,CAAC;AAED;;;;;GAKG;AACI,KAAK,UAAU,iBAAiB,CAAC,QAAgB;IACtD,OAAO,MAAM,IAAA,yBAAuB,EAAC,QAAQ,CAAC,CAAC;AACjD,CAAC;AAED;;;;;;GAMG;AACI,KAAK,UAAU,mBAAmB,CACvC,SAAiB,EAAE,MAA0B;IAE7C,OAAO,MAAM,IAAA,2BAAyB,EAAC,SAAS,EAAE,MAAM,CAAC,CAAC;AAC5D,CAAC"}
@@ -78,6 +78,17 @@ export declare class VFSDispatcher {
78
78
  * @returns A Promise resolving to a Result containing the file contents as a Buffer.
79
79
  */
80
80
  readBinary(pathStr: string): Promise<Result<Buffer>>;
81
+ /**
82
+ * Resolves a lazy link through the provider that owns it.
83
+ *
84
+ * This is deliberately distinct from {@link list}: a structural traversal
85
+ * can display an unresolved link without causing its provider to fetch the
86
+ * target from a remote service.
87
+ *
88
+ * @param pathStr - Absolute path of the provider-defined link.
89
+ * @returns The resolved target path, or an error if unsupported or absent.
90
+ */
91
+ linkTarget_resolve(pathStr: string): Promise<Result<string>>;
81
92
  }
82
93
  /** Global instance of VFSDispatcher singleton. */
83
94
  export declare const vfsDispatcher: VFSDispatcher;
@@ -105,7 +105,9 @@ class VFSDispatcher {
105
105
  resolvedPathStr = await this.pathResolver(pathStr);
106
106
  }
107
107
  catch (e) {
108
- // Fall back cleanly to the original path on failure
108
+ // Deliberate absorption: for a read-only listing, the logical
109
+ // path is a valid fallback (the provider lists what it can);
110
+ // contrast cp(), where a guessed path could write wrongly.
109
111
  }
110
112
  }
111
113
  const nativeResult = await this.defaultProvider.list(resolvedPathStr, options);
@@ -127,7 +129,7 @@ class VFSDispatcher {
127
129
  return provider.list(resolvedPath, options);
128
130
  }
129
131
  catch (e) {
130
- // Fall back cleanly to the original path on failure
132
+ // Deliberate absorption: same read-only-listing rationale as above.
131
133
  }
132
134
  }
133
135
  return provider.list(pathStr, options);
@@ -143,16 +145,27 @@ class VFSDispatcher {
143
145
  async cp(src, dest, options) {
144
146
  const provider = this.provider_get(src);
145
147
  if (provider === this.defaultProvider && this.pathResolver) {
146
- let resolvedSrc = src;
147
- let resolvedDest = dest;
148
+ // A copy must never proceed on a guessed path: an unresolved source
149
+ // copies the wrong thing, an unresolved destination writes to the wrong
150
+ // place. Resolution failure fails the copy.
151
+ let resolvedSrc;
152
+ let resolvedDest;
148
153
  try {
149
154
  resolvedSrc = await this.pathResolver(src);
150
155
  }
151
- catch (e) { }
156
+ catch (e) {
157
+ const msg = e instanceof Error ? e.message : String(e);
158
+ cumin_1.errorStack.stack_push("error", `cp: cannot resolve source path ${src}: ${msg}`);
159
+ return false;
160
+ }
152
161
  try {
153
162
  resolvedDest = await this.pathResolver(dest);
154
163
  }
155
- catch (e) { }
164
+ catch (e) {
165
+ const msg = e instanceof Error ? e.message : String(e);
166
+ cumin_1.errorStack.stack_push("error", `cp: cannot resolve destination path ${dest}: ${msg}`);
167
+ return false;
168
+ }
156
169
  return provider.cp(resolvedSrc, resolvedDest, options);
157
170
  }
158
171
  return provider.cp(src, dest, options);
@@ -185,6 +198,24 @@ class VFSDispatcher {
185
198
  cumin_1.errorStack.stack_push("error", `Binary file read not supported for path: ${pathStr}`);
186
199
  return (0, cumin_1.Err)();
187
200
  }
201
+ /**
202
+ * Resolves a lazy link through the provider that owns it.
203
+ *
204
+ * This is deliberately distinct from {@link list}: a structural traversal
205
+ * can display an unresolved link without causing its provider to fetch the
206
+ * target from a remote service.
207
+ *
208
+ * @param pathStr - Absolute path of the provider-defined link.
209
+ * @returns The resolved target path, or an error if unsupported or absent.
210
+ */
211
+ async linkTarget_resolve(pathStr) {
212
+ const provider = this.provider_get(pathStr);
213
+ if (provider.linkTarget_resolve) {
214
+ return provider.linkTarget_resolve(pathStr);
215
+ }
216
+ cumin_1.errorStack.stack_push('error', `Link resolution not supported for path: ${pathStr}`);
217
+ return (0, cumin_1.Err)();
218
+ }
188
219
  }
189
220
  exports.VFSDispatcher = VFSDispatcher;
190
221
  /** Global instance of VFSDispatcher singleton. */