@oneie/sdk 0.15.1 → 0.16.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.
package/dist/media.js ADDED
@@ -0,0 +1,127 @@
1
+ // media — the client half of "list a WHOLE media library in one read".
2
+ //
3
+ // `media:list` is ONE R2 scan per call with a scan budget (`limit`, default 500,
4
+ // R2's own ceiling 1000) and a cursor. From a caller's point of view that budget
5
+ // is a server fact, not a library, so this driver walks the pages and hands back
6
+ // ONE merged answer that still says how short it is.
7
+ //
8
+ // WHY THE OTHER TWO DOORS HAVE NO DRIVER. The test this repo already applies
9
+ // (`boardAllWith` / `bulkAllWith`) is that a hand-written wrapper earns its place
10
+ // by doing the PAGE WALK or the CHUNKING — never by aliasing a receiver that
11
+ // `ask()` already reaches. `media:upload` and `media:generate` are single calls
12
+ // with no budget to walk, so `client.ask("media:generate", { prompt })` IS the
13
+ // API, and a wrapper would only be a second name for the same door.
14
+ //
15
+ // The driver takes an injected `Asker` rather than a SubstrateClient, for the
16
+ // same reason `tasks-bulk` does: the SDK posts the long form (/api/ask/<r>)
17
+ // while the CLI's default host (api.one.ie) only answers the short form
18
+ // (/ask/<r>). One loop, two transports.
19
+ //
20
+ // Pure: no fetch, no node:*, no Worker-unsafe imports. Browser-safe.
21
+ // Types are derived from receivers.ts — it is truth, and this file must never
22
+ // become a second vocabulary for the same door.
23
+ /** A walk of 20 scans at up to 1000 objects each is 20,000 objects — a whole library for every real workspace. */
24
+ export const MEDIA_PAGE_CEILING = 20;
25
+ function errMsg(e) {
26
+ return e instanceof Error ? e.message : String(e);
27
+ }
28
+ /** Per-page counters SUM. `media:list`'s `total`/`scanned`/`byPrefix` describe THIS
29
+ * answer only ("never a workspace total" — the receiver's own describe()), so keeping
30
+ * the first page's would under-report a walk by exactly the pages it walked. */
31
+ function addCounts(a, b) {
32
+ if (!a && !b)
33
+ return undefined;
34
+ const out = { ...(a ?? {}) };
35
+ for (const [k, v] of Object.entries(b ?? {}))
36
+ out[k] = (out[k] ?? 0) + v;
37
+ return out;
38
+ }
39
+ /**
40
+ * Walk `media:list` until `nextCursor` is absent (ceiling 20 pages).
41
+ *
42
+ * Concatenates `items`; SUMS `total`/`scanned`/`byPrefix` (all three are per-page
43
+ * by contract); keeps the first page's `prefixes` (a static catalogue) and
44
+ * `workspace`; keeps the LAST page's `truncated` — the budget that actually bit.
45
+ *
46
+ * A page that fails STOPS the walk with `ok:false` and the unresolved cursor kept,
47
+ * so a partial library never reads as a complete one. Same when the ceiling is hit
48
+ * with a cursor still in hand: `truncated` is synthesised naming the ceiling, because
49
+ * the one thing this walk must never do is let a short read look whole.
50
+ *
51
+ * `truncated` ABSENT IS NOT FALSE. When it is present, `total` is a FLOOR — report
52
+ * it as "at least N".
53
+ */
54
+ export async function mediaListAllWith(ask, req = {}) {
55
+ let first;
56
+ try {
57
+ first = (await ask("media:list", req));
58
+ }
59
+ catch (e) {
60
+ return { ok: false, error: errMsg(e), pages: 0, items: [] };
61
+ }
62
+ if (!first || first.ok === false)
63
+ return { ...(first ?? { ok: false }), pages: first ? 1 : 0 };
64
+ const items = [...(first.items ?? [])];
65
+ let total = first.total;
66
+ let scanned = first.scanned;
67
+ let byPrefix = first.byPrefix;
68
+ let truncated = first.truncated;
69
+ let cursor = first.nextCursor;
70
+ let pages = 1;
71
+ let error;
72
+ const seen = new Set();
73
+ while (cursor && pages < MEDIA_PAGE_CEILING) {
74
+ if (seen.has(cursor)) {
75
+ error = `media:list page ${pages + 1}: cursor repeated (${cursor})`;
76
+ break;
77
+ }
78
+ seen.add(cursor);
79
+ const { cursor: _drop, ...rest } = req;
80
+ let page;
81
+ try {
82
+ page = (await ask("media:list", { ...rest, cursor }));
83
+ }
84
+ catch (e) {
85
+ error = `media:list page ${pages + 1}: ${errMsg(e)}`;
86
+ break;
87
+ }
88
+ if (!page || page.ok === false) {
89
+ error = `media:list page ${pages + 1}: ${page?.error ?? "failed"}`;
90
+ break;
91
+ }
92
+ pages++;
93
+ items.push(...(page.items ?? []));
94
+ if (page.total !== undefined)
95
+ total = (total ?? 0) + page.total;
96
+ if (page.scanned !== undefined)
97
+ scanned = (scanned ?? 0) + page.scanned;
98
+ byPrefix = addCounts(byPrefix, page.byPrefix);
99
+ // The budget that bit LAST is the one still biting; an earlier page's is spent.
100
+ truncated = page.truncated;
101
+ cursor = page.nextCursor;
102
+ }
103
+ const complete = !cursor;
104
+ if (!complete && !truncated) {
105
+ // Stopped early (ceiling, repeated cursor, or a failed page) with objects still
106
+ // unread and the door not saying so. Say it ourselves rather than answer short in silence.
107
+ truncated = {
108
+ rows: items.length,
109
+ reason: error ?? `walk stopped at the ${MEDIA_PAGE_CEILING}-page ceiling with a cursor outstanding`,
110
+ };
111
+ }
112
+ return {
113
+ ...first,
114
+ ok: error ? false : first.ok,
115
+ ...(error ? { error } : {}),
116
+ items,
117
+ ...(total !== undefined ? { total } : {}),
118
+ ...(scanned !== undefined ? { scanned } : {}),
119
+ ...(byPrefix ? { byPrefix } : {}),
120
+ pages,
121
+ // ABSENT IS NOT FALSE — never write the key when the answer is whole.
122
+ ...(truncated ? { truncated } : {}),
123
+ // Absent = you have them all. Stopped early → keep the cursor so the caller can resume.
124
+ nextCursor: complete ? undefined : cursor,
125
+ };
126
+ }
127
+ //# sourceMappingURL=media.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media.js","sourceRoot":"","sources":["../src/media.ts"],"names":[],"mappings":"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"}