@hanzo/build 0.2.63 → 0.2.64

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.
@@ -0,0 +1,12 @@
1
+ /**
2
+ * One completion from Hanzo's own models, asked with the person's own bearer so
3
+ * it is attributed to them and metered as theirs.
4
+ *
5
+ * POST /v1/chat/completions {model, messages, max_tokens} → {choices: [{message: {content}}]}
6
+ */
7
+ import { type Target } from './call.ts';
8
+ /** The quick model a plugin thinks with: planning a search, drafting a template. */
9
+ export declare const QUICK = "enso-flash";
10
+ export declare function ask(t: Target, system: string, user: string, signal?: AbortSignal, tokens?: number): Promise<string>;
11
+ /** The first JSON object in a model's answer, or null: a model may talk around it. */
12
+ export declare function json(said: string): Record<string, unknown> | null;
@@ -0,0 +1,28 @@
1
+ /**
2
+ * One completion from Hanzo's own models, asked with the person's own bearer so
3
+ * it is attributed to them and metered as theirs.
4
+ *
5
+ * POST /v1/chat/completions {model, messages, max_tokens} → {choices: [{message: {content}}]}
6
+ */
7
+ import { call } from './call.js';
8
+ /** The quick model a plugin thinks with: planning a search, drafting a template. */
9
+ export const QUICK = 'enso-flash';
10
+ export async function ask(t, system, user, signal, tokens = 800) {
11
+ const raw = await call(t, 'POST', '/v1/chat/completions', { model: QUICK, max_tokens: tokens, messages: [{ role: 'system', content: system }, { role: 'user', content: user }] }, { signal });
12
+ const said = raw?.choices?.[0]?.message?.content;
13
+ return typeof said === 'string' ? said : '';
14
+ }
15
+ /** The first JSON object in a model's answer, or null: a model may talk around it. */
16
+ export function json(said) {
17
+ const from = said.indexOf('{');
18
+ const to = said.lastIndexOf('}');
19
+ if (from < 0 || to <= from)
20
+ return null;
21
+ try {
22
+ const v = JSON.parse(said.slice(from, to + 1));
23
+ return v && typeof v === 'object' && !Array.isArray(v) ? v : null;
24
+ }
25
+ catch {
26
+ return null;
27
+ }
28
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Hanzo Studio: a creation is a run of a template, its files kept in the Library.
3
+ *
4
+ * GET /v1/studio/templates {data: [template]} the public catalog, then the org's own
5
+ * POST /v1/studio/runs {template, input, title?, parent?} → 201 run, queued
6
+ * GET /v1/studio/runs/{id} the run: status, text, outputs
7
+ * POST /v1/studio/runs/{id}/cancel stop it; what it reserved is released
8
+ *
9
+ * A run is priced and its estimate reserved against the org's wallet before it
10
+ * is queued (402 when the wallet cannot cover it). `parent` makes the run the
11
+ * next version of that one. Its outputs are Library items: their `url` is
12
+ * signed and expires, their `origin` is the app path that opens the run in
13
+ * Studio and does not.
14
+ */
15
+ import { type Target } from './call.ts';
16
+ import { type Item } from './library.ts';
17
+ export interface Run {
18
+ id: string;
19
+ /** queued, running, succeeded, failed or cancelled. */
20
+ status: string;
21
+ title: string;
22
+ /** What the run's writing step said, when its product is words. */
23
+ text: string;
24
+ outputs: Item[];
25
+ /** Why it failed, in the platform's words, or ''. */
26
+ error: string;
27
+ }
28
+ export interface Start {
29
+ template: string;
30
+ input: Record<string, unknown>;
31
+ title?: string;
32
+ parent?: string;
33
+ }
34
+ export declare function run(raw: unknown): Run;
35
+ /** A run that has ended, one way or the other. */
36
+ export declare const ended: (r: Run) => boolean;
37
+ /** The ids of the templates this org may run. */
38
+ export declare function templates(t: Target, init?: {
39
+ signal?: AbortSignal;
40
+ }): Promise<string[]>;
41
+ /**
42
+ * Start a run and wait for it to end. Aborted, the run is cancelled so its
43
+ * reservation is released; a run that fails is thrown with its reason.
44
+ */
45
+ export declare function make(t: Target, s: Start, signal?: AbortSignal): Promise<Run>;
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Hanzo Studio: a creation is a run of a template, its files kept in the Library.
3
+ *
4
+ * GET /v1/studio/templates {data: [template]} the public catalog, then the org's own
5
+ * POST /v1/studio/runs {template, input, title?, parent?} → 201 run, queued
6
+ * GET /v1/studio/runs/{id} the run: status, text, outputs
7
+ * POST /v1/studio/runs/{id}/cancel stop it; what it reserved is released
8
+ *
9
+ * A run is priced and its estimate reserved against the org's wallet before it
10
+ * is queued (402 when the wallet cannot cover it). `parent` makes the run the
11
+ * next version of that one. Its outputs are Library items: their `url` is
12
+ * signed and expires, their `origin` is the app path that opens the run in
13
+ * Studio and does not.
14
+ */
15
+ import { call, Refusal, seg } from './call.js';
16
+ import { item } from './library.js';
17
+ const str = (v) => (typeof v === 'string' ? v : '');
18
+ const obj = (v) => (v && typeof v === 'object' ? v : {});
19
+ export function run(raw) {
20
+ const o = obj(raw);
21
+ const e = obj(o.error);
22
+ return {
23
+ id: str(o.id),
24
+ status: str(o.status),
25
+ title: str(o.title),
26
+ text: str(o.text),
27
+ outputs: (Array.isArray(o.outputs) ? o.outputs : []).map(item).filter((x) => x !== null),
28
+ error: str(e.detail) || str(e.title),
29
+ };
30
+ }
31
+ /** A run that has ended, one way or the other. */
32
+ export const ended = (r) => r.status !== 'queued' && r.status !== 'running' && r.status !== '';
33
+ /** The ids of the templates this org may run. */
34
+ export async function templates(t, init) {
35
+ const raw = obj(await call(t, 'GET', '/v1/studio/templates', undefined, init));
36
+ return (Array.isArray(raw.data) ? raw.data : []).map((x) => str(obj(x).id)).filter(Boolean);
37
+ }
38
+ /** How often a run is read while it works, and the longest it is waited for. */
39
+ const EVERY = 2_000;
40
+ const LONGEST = 5 * 60_000;
41
+ const pause = (ms, signal) => new Promise((done, fail) => {
42
+ const id = setTimeout(done, ms);
43
+ signal?.addEventListener('abort', () => {
44
+ clearTimeout(id);
45
+ fail(signal.reason);
46
+ }, { once: true });
47
+ });
48
+ /**
49
+ * Start a run and wait for it to end. Aborted, the run is cancelled so its
50
+ * reservation is released; a run that fails is thrown with its reason.
51
+ */
52
+ export async function make(t, s, signal) {
53
+ let r = run(await call(t, 'POST', '/v1/studio/runs', s, { signal }).catch((e) => {
54
+ throw e instanceof Refusal && e.status === 402 ? new Error('Your balance does not cover it. Add credit in Settings › Billing.') : e;
55
+ }));
56
+ if (!r.id)
57
+ throw new Error('Studio started the run and named no id');
58
+ const id = r.id;
59
+ const stop = () => void call(t, 'POST', `/v1/studio/runs/${seg(id)}/cancel`, {}).catch(() => undefined);
60
+ signal?.addEventListener('abort', stop, { once: true });
61
+ try {
62
+ const until = Date.now() + LONGEST;
63
+ while (!ended(r)) {
64
+ if (Date.now() > until)
65
+ throw new Error('Studio is still making it. It will be in your Library when it is done.');
66
+ await pause(EVERY, signal);
67
+ r = run(await call(t, 'GET', `/v1/studio/runs/${seg(id)}`, undefined, { signal }));
68
+ }
69
+ }
70
+ finally {
71
+ signal?.removeEventListener('abort', stop);
72
+ }
73
+ if (r.status !== 'succeeded')
74
+ throw new Error(r.error || `Studio could not make it (${r.status})`);
75
+ return r;
76
+ }
package/lib/carry.d.ts CHANGED
@@ -1,10 +1,22 @@
1
+ import { type ReactNode } from 'react';
1
2
  import { type Target } from './api/call.ts';
2
3
  import { type GearState } from './gear.ts';
4
+ import type { Composer, Prep, Turn } from './plugin.ts';
3
5
  import type { Shelf } from './plus.tsx';
4
6
  import type { Chip } from './prompt.tsx';
7
+ /** What the surface lends the plugins: its draft, its files, its way about. */
8
+ export type Lent = Omit<Composer, 'target' | 'show'>;
5
9
  export interface Carry {
6
10
  gear: GearState;
7
11
  skills: Shelf;
12
+ /** The plugins that run for this person (`@` lists the same). */
13
+ plugins: Shelf;
14
+ /** A dialog a plugin opened, for the surface to draw; null when none is. */
15
+ dialog: ReactNode;
16
+ /** Whether a plugin that prepares a message is on. */
17
+ preparing: boolean;
18
+ /** What the plugins that are on add to the message about to go. */
19
+ prep: (turn: Turn, signal: AbortSignal) => Promise<Prep>;
8
20
  /** The chips after `+`: the skills on, Research, and Plan. */
9
21
  on: Chip[];
10
22
  /** The words the gear adds to every message, '' when none. */
@@ -14,4 +26,4 @@ export interface Carry {
14
26
  * The conversation `key` names (`''` for one not begun), for target `t`.
15
27
  * `customize(tab)` opens Dev's Customize on that tab.
16
28
  */
17
- export declare function useCarry(t: Target, key: string, customize: (tab: 'skills') => void): Carry;
29
+ export declare function useCarry(t: Target, key: string, customize: (tab: 'skills') => void, lent: Lent): Carry;
package/lib/carry.js CHANGED
@@ -16,11 +16,12 @@ import { jsx as _jsx } from "react/jsx-runtime";
16
16
  * (Chat its agents, Dev its devices) beside these.
17
17
  */
18
18
  import { BookOpen, ListChecks, ScrollText } from '@hanzogui/lucide-icons-2';
19
- import { useEffect, useMemo, useState } from 'react';
19
+ import { useEffect, useMemo, useRef, useState } from 'react';
20
20
  import { call, query, unwrap } from './api/call.js';
21
21
  import { active, authored, document, nameOf as skillOf } from './api/skills.js';
22
22
  import { useRead } from './data.js';
23
23
  import { useGear } from './gear.js';
24
+ import { active as lighted, prep, shelf as pluginShelf, usePlugins } from './plugins/index.js';
24
25
  /** The most of each skill a message carries. */
25
26
  const SKILL_MAX = 16_000;
26
27
  /** The memories every message carries at most, newest first. */
@@ -56,8 +57,23 @@ async function said(t, skills, memory, mode) {
56
57
  * The conversation `key` names (`''` for one not begun), for target `t`.
57
58
  * `customize(tab)` opens Dev's Customize on that tab.
58
59
  */
59
- export function useCarry(t, key, customize) {
60
+ export function useCarry(t, key, customize, lent) {
60
61
  const gear = useGear(t, key);
62
+ const [dialog, show] = useState(null);
63
+ // The composer a plugin acts on, read when it acts: the draft moves under it.
64
+ const lentNow = useRef(lent);
65
+ lentNow.current = lent;
66
+ const composer = useMemo(() => ({
67
+ target: t,
68
+ get draft() {
69
+ return lentNow.current.draft;
70
+ },
71
+ setDraft: (x) => lentNow.current.setDraft(x),
72
+ attach: (f) => lentNow.current.attach(f),
73
+ go: (h) => lentNow.current.go(h),
74
+ show,
75
+ }), [t]);
76
+ const found = usePlugins(t);
61
77
  const signed = Boolean(t.token());
62
78
  const list = useRead(signed ? () => active(t) : null, [], [t, signed]);
63
79
  const names = useMemo(() => list.value.map((s) => skillOf(s.name)).filter(Boolean), [list.value]);
@@ -72,10 +88,15 @@ export function useCarry(t, key, customize) {
72
88
  manage: { label: 'Manage skills', onPress: () => customize('skills') },
73
89
  browse: { label: 'Browse skills', onPress: () => customize('skills') },
74
90
  };
91
+ const plugins = pluginShelf(found, gear, composer);
92
+ const lit = lighted(found.plugins, gear.gear);
75
93
  const on = [
76
94
  ...skills.map((n) => ({ id: `skill:${n}`, label: n, icon: _jsx(ScrollText, { size: 14 }), onRemove: () => gear.toggle('skills', n) })),
77
95
  ...(research ? [{ id: 'research', label: 'Research', icon: _jsx(BookOpen, { size: 14 }), onRemove: () => gear.set({ research: false }) }] : []),
78
96
  ...(mode === 'plan' ? [{ id: 'plan', label: 'Plan', icon: _jsx(ListChecks, { size: 14 }), onRemove: () => gear.set({ mode: 'auto' }) }] : []),
97
+ ...lit
98
+ .filter((p) => p.id !== 'research')
99
+ .map((p) => ({ id: `plugin:${p.id}`, label: p.name, icon: p.icon, onRemove: () => gear.toggle('plugins', p.id) })),
79
100
  ];
80
101
  const signedIn = Boolean(t.token());
81
102
  const [text, setText] = useState('');
@@ -91,5 +112,14 @@ export function useCarry(t, key, customize) {
91
112
  // `skills` is read through `asked`, its contents.
92
113
  // eslint-disable-next-line react-hooks/exhaustive-deps
93
114
  }, [t, signedIn, asked, memory, mode]);
94
- return { gear, skills: shelf, on, text };
115
+ return {
116
+ gear,
117
+ skills: shelf,
118
+ plugins,
119
+ dialog,
120
+ on,
121
+ text,
122
+ preparing: lit.length > 0,
123
+ prep: (turn, signal) => prep(found.plugins, gear.gear, turn, composer, signal),
124
+ };
95
125
  }
package/lib/index.d.ts CHANGED
@@ -54,12 +54,19 @@ export { Plus, type Link, type PlusProps, type Row as ShelfRow, type Shelf, type
54
54
  export { BARE, gearOf, MODES, useGear, useLanguage, type Gear, type GearState, type Mode as GearMode } from './gear.ts';
55
55
  export { useCarry, type Carry } from './carry.tsx';
56
56
  export { Dictation } from './mic.tsx';
57
- export type { Composer as PluginComposer, Plugin, Prep, Turn } from './plugin.ts';
58
57
  export { artifacts, blob, lead, renders, Reply, Served, speakable, speaker, type Artifact, type Listen } from './reply.tsx';
59
58
  export { frames, Page, Panel, PanelToggle, type Kind, type PageProps, type PanelProps, type Suggestion } from './panel.tsx';
60
59
  export { SideProvider, useSplit, type Split } from './side.tsx';
61
60
  export { PrefsProvider } from './prefs.tsx';
62
61
  export { kinds, Summary, useKinds, type Entry, type Section } from './summary.tsx';
62
+ /**
63
+ * The composer's plugins, the same in Chat and Dev: `usePlugins` answers those
64
+ * that run for this person, `shelf` is the `+` menu's Plugins shelf, and `prep`
65
+ * asks the ones that are on what a message carries (Deep research is the
66
+ * Research switch, `research`).
67
+ */
68
+ export { active, BUILD, merge, prep, shelf, usePlugins, research, type Plugins } from './plugins/index.ts';
69
+ export type { Composer as PluginComposer, Plugin, Prep, Turn } from './plugin.ts';
63
70
  export { address, destination, located, name, PAGE, SEARCH, useDeck, useKey, usePanel, useShown, type Deck, type Tab, type Tabs } from './tabs.ts';
64
71
  /**
65
72
  * Up to three suggestions under the composer (above it on a phone), each from
package/lib/index.js CHANGED
@@ -54,6 +54,13 @@ export { frames, Page, Panel, PanelToggle } from './panel.js';
54
54
  export { SideProvider, useSplit } from './side.js';
55
55
  export { PrefsProvider } from './prefs.js';
56
56
  export { kinds, Summary, useKinds } from './summary.js';
57
+ /**
58
+ * The composer's plugins, the same in Chat and Dev: `usePlugins` answers those
59
+ * that run for this person, `shelf` is the `+` menu's Plugins shelf, and `prep`
60
+ * asks the ones that are on what a message carries (Deep research is the
61
+ * Research switch, `research`).
62
+ */
63
+ export { active, BUILD, merge, prep, shelf, usePlugins, research } from './plugins/index.js';
57
64
  export { address, destination, located, name, PAGE, SEARCH, useDeck, useKey, usePanel, useShown } from './tabs.js';
58
65
  /**
59
66
  * Up to three suggestions under the composer (above it on a phone), each from
package/lib/landing.js CHANGED
@@ -39,7 +39,7 @@ import { useCarry } from './carry.js';
39
39
  import { Suggestions, useSuggestions } from './suggestions.js';
40
40
  import { MEASURE, Prompt, useEar } from './prompt.js';
41
41
  import { Monitor as Device } from '@hanzogui/lucide-icons-2';
42
- import { compose, Files, pick } from './tools.js';
42
+ import { compose, Files, pick, read as readFiles } from './tools.js';
43
43
  import { useSpoken } from './voice.js';
44
44
  /** One vocabulary for the mode, on New and in a workspace. */
45
45
  export const MODES = [
@@ -114,7 +114,27 @@ export function Landing({ onStarted }) {
114
114
  const voice = useVoice({ speech: useEar(t), language: useSpoken(), ...useDictation(draft, setDraft) });
115
115
  const talk = useTalk({ baseUrl: t.api, token: () => t.token(), ...(t.org ? { org: t.org } : {}) });
116
116
  // What the run carries beside the ask: skills, memory and the mode, as Chat's turns do.
117
- const carry = useCarry(t, '', (tab) => host.go(path({ kind: 'customize', tab })));
117
+ const carry = useCarry(t, '', (tab) => host.go(path({ kind: 'customize', tab })), {
118
+ draft,
119
+ setDraft,
120
+ // A run reads text: a file that is one rides the ask, a picture goes with a chat.
121
+ attach: (list) => {
122
+ const text = list.filter((f) => !f.type.startsWith('image/'));
123
+ if (text.length < list.length)
124
+ setNote('A run reads text files; send a picture in Chat.');
125
+ if (text.length) {
126
+ const dt = new DataTransfer();
127
+ for (const f of text)
128
+ dt.items.add(f);
129
+ void readFiles(files, dt.files).then(({ files: next, note: why }) => {
130
+ setFiles(next);
131
+ if (why)
132
+ setNote(why);
133
+ });
134
+ }
135
+ },
136
+ go: (href) => (href.startsWith('http') ? host.open(href) : host.go(href)),
137
+ });
118
138
  const mode = carry.gear.gear.mode === 'plan' ? 'plan' : 'build';
119
139
  const hints = useSuggestions(t);
120
140
  // The chosen codebase's environment, so New can say when it has none yet.
@@ -181,8 +201,14 @@ export function Landing({ onStarted }) {
181
201
  setBusy(true);
182
202
  setNote('');
183
203
  try {
204
+ // What the plugins that are on add: words for the run, or an answer of their own.
205
+ const prepped = carry.preparing ? await carry.prep({ text: draft.trim(), files: [], thread: '' }, new AbortController().signal) : {};
206
+ if (prepped.reply && !prepped.system) {
207
+ setNote(prepped.reply);
208
+ return;
209
+ }
184
210
  const run = await start(t, {
185
- prompt: compose([draft.trim(), carry.text].filter(Boolean).join('\n\n---\n'), files),
211
+ prompt: compose([draft.trim(), carry.text, prepped.system ?? ''].filter(Boolean).join('\n\n---\n'), files),
186
212
  // The name alone. The org rides the request, and a slash is not a repo name.
187
213
  // An empty base or place is not sent: the default branch, and the sandbox.
188
214
  repo: repo?.name ?? hub?.full_name,
@@ -281,9 +307,10 @@ export function Landing({ onStarted }) {
281
307
  : `${codebase} has no environment yet, so every run starts it bare.` }), env.value.state === 'proposed' && env.value.session ? (_jsx(Button, { size: "sm", variant: "outline", onPress: () => host.go(env.value.session), children: "Review" })) : (_jsx(Button, { size: "sm", onPress: () => setOffering(true), children: "Set up environment" }))] })) : null, note || unhonoured(mode, place.id) || mind.note ? (_jsx(SizableText, { size: "$1", color: "$soft", role: "status", children: note || unhonoured(mode, place.id) || mind.note })) : null, _jsx(Prompt, { framed: true, value: draft, onChange: setDraft, onSend: () => void send(), busy: busy, label: "Describe a task or ask a question", head: head, plus: {
282
308
  upload: () => pick(files, setFiles, setNote),
283
309
  skills: carry.skills,
310
+ plugins: carry.plugins,
284
311
  devices,
285
312
  memory: { on: carry.gear.gear.memory, set: (on) => carry.gear.set({ memory: on }) },
286
- }, on: carry.on, slash: carry.skills, mode: { value: carry.gear.gear.mode, set: (m) => carry.gear.set({ mode: m }) }, where: where, below: _jsx(Suggestions, { rows: hints.rows, onPick: setDraft, onDismiss: hints.dismiss }), mind: mind, limits: limits, onUpgrade: () => host.go(path({ kind: 'screen', screen: 'plans' })), voice: voice, language: prefs.language ?? null, onLanguage: (id) => void savePrefs({ language: id }), talk: talk })] })] }), _jsx(Publish, { source: adding, onClose: () => setAdding(null) }), codebase ? (_jsx(SetupDialog, { repo: codebase, homes: homes, open: offering, onOpenChange: setOffering, onStart: setup, onRepo: choose, onSaved: () => {
313
+ }, on: carry.on, slash: carry.skills, at: carry.plugins, mode: { value: carry.gear.gear.mode, set: (m) => carry.gear.set({ mode: m }) }, where: where, below: _jsx(Suggestions, { rows: hints.rows, onPick: setDraft, onDismiss: hints.dismiss }), mind: mind, limits: limits, onUpgrade: () => host.go(path({ kind: 'screen', screen: 'plans' })), voice: voice, language: prefs.language ?? null, onLanguage: (id) => void savePrefs({ language: id }), talk: talk })] })] }), _jsx(Publish, { source: adding, onClose: () => setAdding(null) }), carry.dialog, codebase ? (_jsx(SetupDialog, { repo: codebase, homes: homes, open: offering, onOpenChange: setOffering, onStart: setup, onRepo: choose, onSaved: () => {
287
314
  setOffering(false);
288
315
  env.reload();
289
316
  } })) : null] }));
package/lib/pdf.d.ts ADDED
@@ -0,0 +1,139 @@
1
+ /**
2
+ * A PDF, read where it is: its text page by page, and what its structure says
3
+ * about it — version, pages, metadata, encryption, how often it was revised
4
+ * after it was written, and whether each signature still covers the bytes it
5
+ * signed. Nothing leaves the browser.
6
+ *
7
+ * Text comes out of each page's content streams (and the forms they draw),
8
+ * decoded with each font's ToUnicode map: Flate is undone by the platform's own
9
+ * `DecompressionStream`, objects packed into object streams are unpacked, and a
10
+ * font without a map is read as single-byte Latin. What it cannot read it says
11
+ * it cannot: an encrypted file, a page that is only pictures (a scan needs OCR),
12
+ * a stream in a filter other than Flate.
13
+ *
14
+ * A signature is checked for integrity, not trust: that its byte range starts at
15
+ * the first byte, frames exactly its own signature, and reaches the end of the
16
+ * file (or how many bytes were added after it), and that the digest the
17
+ * signature carries (CMS `messageDigest`) is the digest of those bytes. Whether
18
+ * the signer's certificate is trusted is not decided here.
19
+ */
20
+ /** A name (`/Type`), a string's bytes, an indirect reference, an operator in a content stream. */
21
+ export declare class Name {
22
+ readonly n: string;
23
+ constructor(n: string);
24
+ }
25
+ export declare class Str {
26
+ readonly s: string;
27
+ constructor(s: string);
28
+ }
29
+ export declare class Ref {
30
+ readonly n: number;
31
+ constructor(n: number);
32
+ }
33
+ export declare class Op {
34
+ readonly o: string;
35
+ constructor(o: string);
36
+ }
37
+ export type Dict = Map<string, Value>;
38
+ export type Value = number | boolean | null | Name | Str | Ref | Op | Value[] | Dict;
39
+ /** The largest file read. */
40
+ export declare const LARGEST: number;
41
+ /** Bytes as a string of the same length, one char per byte. */
42
+ export declare function latin(b: Uint8Array): string;
43
+ /** A cursor over PDF syntax: the objects of a file, or the operators of a content stream. */
44
+ export declare class Lexer {
45
+ readonly src: string;
46
+ at: number;
47
+ constructor(src: string, at?: number);
48
+ skip(): void;
49
+ /** The next value, or undefined at the end. */
50
+ next(): Value | undefined;
51
+ private literal;
52
+ }
53
+ interface Obj {
54
+ value: Value;
55
+ /** A stream's bytes as stored, still encoded. */
56
+ data?: Uint8Array;
57
+ }
58
+ export interface Doc {
59
+ bytes: Uint8Array;
60
+ src: string;
61
+ objects: Map<number, Obj>;
62
+ }
63
+ export declare function resolve(doc: Doc, v: Value | undefined, depth?: number): Value | undefined;
64
+ /** Undo a stream's filters: Flate, ASCII85 and hex, in the order named. Null for one it cannot undo. */
65
+ export declare function decode(doc: Doc, o: Obj): Promise<Uint8Array | null>;
66
+ /** ASCII85, as PDF writes it: `z` for four zeros, ending at `~>`. */
67
+ export declare function a85(s: string): Uint8Array;
68
+ export declare function inflate(data: Uint8Array): Promise<Uint8Array | null>;
69
+ /** Every object in the file, a later definition of a number winning, and those packed in object streams. */
70
+ export declare function open(bytes: Uint8Array): Promise<Doc>;
71
+ /** The pages in reading order, each with the resources it inherits. */
72
+ export declare function pages(doc: Doc): {
73
+ page: Dict;
74
+ resources: Dict;
75
+ }[];
76
+ /** A font as text reads it: how many bytes a code takes, what each code says, and how far it moves the pen. */
77
+ export interface Font {
78
+ width: number;
79
+ map: Map<number, string> | null;
80
+ /** Each code's advance, in thousandths of an em; a code not listed advances `dw`. */
81
+ advance: Map<number, number>;
82
+ dw: number;
83
+ }
84
+ /** A ToUnicode CMap: its code width and its map. */
85
+ export declare function cmap(s: string, width: number): Pick<Font, 'width' | 'map'>;
86
+ /** A simple font's /Differences as text, where each glyph name says what it is. */
87
+ export declare function differences(v: Value | undefined): Map<number, string> | null;
88
+ /** The codes a string holds, `width` bytes each. */
89
+ export declare function codes(s: string, width: number): number[];
90
+ /** What one code says in a font. A two-byte font with no map says nothing: its codes are glyph numbers. */
91
+ export declare function say(code: number, f: Pick<Font, 'width' | 'map'> | undefined): string;
92
+ /** Each page's text, in reading order. */
93
+ export declare function text(doc: Doc): Promise<string[]>;
94
+ /** A PDF text string: UTF-16 or UTF-8 with its mark, else one byte a character. */
95
+ export declare function words(s: Str | Value | undefined): string;
96
+ /** A PDF date (`D:20261020113000-07'00'`) as a person reads it, or the string as it was. */
97
+ export declare function date(s: string): string;
98
+ export interface Signature {
99
+ /** Who the signature dictionary names, or ''. */
100
+ name: string;
101
+ reason: string;
102
+ location: string;
103
+ time: string;
104
+ /** Its SubFilter: adbe.pkcs7.detached, ETSI.CAdES.detached, … */
105
+ filter: string;
106
+ /** The byte range starts at the first byte and frames exactly the signature's own bytes. */
107
+ framed: boolean;
108
+ /** Bytes in the file after the end of what was signed; 0 when the signature covers the whole file. */
109
+ after: number;
110
+ /** The digest the signature carries matches the signed bytes; null when it was not checked. */
111
+ intact: boolean | null;
112
+ /** The digest that was checked, `SHA-256`, or why none was. */
113
+ digest: string;
114
+ }
115
+ export interface Check {
116
+ version: string;
117
+ pages: number;
118
+ encrypted: boolean;
119
+ /** How many times it was saved: 1 is as first written, each incremental update adds one. */
120
+ saves: number;
121
+ info: Record<string, string>;
122
+ /** What is wrong with its structure, in words; empty when nothing is. */
123
+ problems: string[];
124
+ signatures: Signature[];
125
+ }
126
+ /** The digest a CMS signature says it signed: the value of its messageDigest attribute, or ''. */
127
+ export declare function claimed(der: string): string;
128
+ /** What the file's structure says about it. */
129
+ export declare function check(doc: Doc): Promise<Check>;
130
+ export interface Read {
131
+ check: Check;
132
+ /** Each page's text; empty when the file is encrypted. */
133
+ text: string[];
134
+ }
135
+ /** Read a PDF: its structure, and its text when it is not encrypted. */
136
+ export declare function read(bytes: Uint8Array): Promise<Read>;
137
+ /** What a read found, in words a model is given. */
138
+ export declare function report(file: string, r: Read): string;
139
+ export {};