@bitflow/core 0.5.4 → 0.7.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.
- package/dist/attempt.d.ts +67 -0
- package/dist/condition.d.ts +38 -0
- package/dist/engine.d.ts +190 -0
- package/dist/errors.d.ts +28 -0
- package/dist/i18n.d.ts +35 -0
- package/dist/id.d.ts +6 -0
- package/dist/image.d.ts +40 -0
- package/dist/index.d.ts +13 -11
- package/dist/index.js +1410 -0
- package/dist/registry.d.ts +118 -0
- package/dist/schema.d.ts +431 -0
- package/dist/score.d.ts +18 -0
- package/dist/styles.d.ts +14 -0
- package/dist/theme.css +451 -0
- package/dist/validate.d.ts +19 -0
- package/dist/validateCondition.d.ts +13 -0
- package/package.json +26 -24
- package/README.md +0 -9
- package/dist/bits.d.ts +0 -128
- package/dist/bitsSchema.d.ts +0 -150
- package/dist/do.d.ts +0 -37
- package/dist/doSchema.d.ts +0 -1478
- package/dist/findLast.d.ts +0 -1
- package/dist/flow.d.ts +0 -169
- package/dist/flowSchema.d.ts +0 -2520
- package/dist/groupBy.d.ts +0 -1
- package/dist/index.cjs.js +0 -732
- package/dist/index.cjs.js.map +0 -7
- package/dist/index.esm.mjs +0 -703
- package/dist/index.esm.mjs.map +0 -7
- package/dist/lerpColor.d.ts +0 -1
- package/dist/levenshtein.d.ts +0 -1
- package/dist/uuid.d.ts +0 -1
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { type Result } from "./errors";
|
|
2
|
+
import { type AttemptSnapshot, type BitflowDocument, type Confidence } from "./schema";
|
|
3
|
+
export declare const createAttempt: (doc: BitflowDocument, options?: {
|
|
4
|
+
attemptId?: string;
|
|
5
|
+
now?: Date;
|
|
6
|
+
/** Injectable only so tests can draw pools deterministically. */
|
|
7
|
+
random?: () => number;
|
|
8
|
+
}) => Result<AttemptSnapshot>;
|
|
9
|
+
/**
|
|
10
|
+
* Validates a snapshot from the host against the document it claims to belong
|
|
11
|
+
* to. Callers must treat a failure as "keep the current attempt untouched" —
|
|
12
|
+
* a half-restored attempt would silently lose a learner's work.
|
|
13
|
+
*/
|
|
14
|
+
export declare const restoreAttempt: (doc: BitflowDocument, input: unknown) => Result<AttemptSnapshot>;
|
|
15
|
+
export declare const abandonAttempt: (snapshot: AttemptSnapshot, now?: Date) => AttemptSnapshot;
|
|
16
|
+
/** A durable answer change, without evaluating it. */
|
|
17
|
+
export declare const setAnswer: (snapshot: AttemptSnapshot, nodeId: string, answer: unknown, now?: Date) => AttemptSnapshot;
|
|
18
|
+
export declare const setConfidence: (snapshot: AttemptSnapshot, nodeId: string, confidence: Confidence, now?: Date) => AttemptSnapshot;
|
|
19
|
+
export declare const setReasoning: (snapshot: AttemptSnapshot, nodeId: string, reasoning: string, now?: Date) => AttemptSnapshot;
|
|
20
|
+
/**
|
|
21
|
+
* Runs the bit's evaluator and stores answer, result and try count together, so
|
|
22
|
+
* a snapshot never shows a result that belongs to a different answer.
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* An attempt already sitting at `nodeId`.
|
|
26
|
+
*
|
|
27
|
+
* For previewing one step of a long flow: reaching the last task of a
|
|
28
|
+
* twenty-step assessment by answering the nineteen in front of it is not a
|
|
29
|
+
* reasonable thing to ask of someone editing the twentieth. The history holds
|
|
30
|
+
* only this node, so there is nothing behind it to go back to — a preview
|
|
31
|
+
* starting in the middle should not pretend the middle was reached.
|
|
32
|
+
*/
|
|
33
|
+
export declare const attemptAt: (doc: BitflowDocument, nodeId: string, options?: {
|
|
34
|
+
attemptId?: string;
|
|
35
|
+
now?: Date;
|
|
36
|
+
random?: () => number;
|
|
37
|
+
}) => Result<AttemptSnapshot>;
|
|
38
|
+
export declare const evaluateNode: (doc: BitflowDocument, snapshot: AttemptSnapshot, nodeId: string, answer?: unknown, now?: Date) => Promise<Result<AttemptSnapshot>>;
|
|
39
|
+
/**
|
|
40
|
+
* Records that the learner passed on a node. The try counts (so branching on
|
|
41
|
+
* `tries` sees it) but no result is stored, which keeps it out of the score.
|
|
42
|
+
*/
|
|
43
|
+
export declare const skipNode: (snapshot: AttemptSnapshot, nodeId: string, now?: Date) => AttemptSnapshot;
|
|
44
|
+
/**
|
|
45
|
+
* Clears the result so the learner can answer again. The try count is kept —
|
|
46
|
+
* it is the record of how many attempts it took.
|
|
47
|
+
*/
|
|
48
|
+
export declare const retryNode: (snapshot: AttemptSnapshot, nodeId: string, now?: Date) => AttemptSnapshot;
|
|
49
|
+
export declare const goNext: (doc: BitflowDocument, snapshot: AttemptSnapshot, now?: Date) => AttemptSnapshot;
|
|
50
|
+
/**
|
|
51
|
+
* Steps back through the visited history. The step is popped so going forward
|
|
52
|
+
* again re-evaluates the branch — an answer changed in between must be able to
|
|
53
|
+
* send the learner down a different path.
|
|
54
|
+
*/
|
|
55
|
+
export declare const goPrevious: (doc: BitflowDocument, snapshot: AttemptSnapshot, now?: Date) => AttemptSnapshot;
|
|
56
|
+
export declare const canGoPrevious: (doc: BitflowDocument, snapshot: AttemptSnapshot) => boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Jumps straight to a step the learner has already been to.
|
|
59
|
+
*
|
|
60
|
+
* Only offered when the flow allows free movement, and only backwards: the
|
|
61
|
+
* history is truncated to the step jumped to, exactly as stepping back does, so
|
|
62
|
+
* going forward again re-runs every branch in between. Answers and results stay
|
|
63
|
+
* put — the jump is a change of view, not an undo.
|
|
64
|
+
*/
|
|
65
|
+
export declare const goTo: (doc: BitflowDocument, snapshot: AttemptSnapshot, nodeId: string, now?: Date) => AttemptSnapshot;
|
|
66
|
+
export declare const isComplete: (snapshot: AttemptSnapshot) => boolean;
|
|
67
|
+
export declare const isAtEnd: (doc: BitflowDocument, snapshot: AttemptSnapshot) => boolean;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { BitResult, Condition, ValueRef } from "./schema";
|
|
2
|
+
/**
|
|
3
|
+
* Everything a branch may read out of the running attempt.
|
|
4
|
+
*
|
|
5
|
+
* Built by `conditionContext(doc, snapshot)`; nothing here is derived at
|
|
6
|
+
* comparison time, so replaying the same context always picks the same path.
|
|
7
|
+
*/
|
|
8
|
+
export type ConditionContext = {
|
|
9
|
+
answers: Record<string, unknown>;
|
|
10
|
+
results: Record<string, BitResult>;
|
|
11
|
+
tries: Record<string, number>;
|
|
12
|
+
/** How many times each node has been shown, counted off the history. */
|
|
13
|
+
visits: Record<string, number>;
|
|
14
|
+
/** `0`–`1` per node, for the steps the learner was asked about. */
|
|
15
|
+
confidence: Record<string, number>;
|
|
16
|
+
/** Seconds spent per node, including the stretch in progress. */
|
|
17
|
+
timeSpent: Record<string, number>;
|
|
18
|
+
/** Seconds spent across the whole attempt. */
|
|
19
|
+
totalTimeSpent: number;
|
|
20
|
+
/** Seconds left on the flow's own limit, or `null` when it has none. */
|
|
21
|
+
timeRemaining: number | null;
|
|
22
|
+
/** Node ids oldest first, which is what a `last` scope counts back through. */
|
|
23
|
+
history: string[];
|
|
24
|
+
/** Node id → section id, for a section-scoped count or score. */
|
|
25
|
+
sections: Record<string, string>;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Reads `a.b.0.c` out of a nested value. Returns `undefined` for any missing
|
|
29
|
+
* segment rather than throwing, so a condition that points at a node the
|
|
30
|
+
* learner has not reached yet is simply false instead of fatal.
|
|
31
|
+
*/
|
|
32
|
+
export declare const getPath: (value: unknown, path?: string) => unknown;
|
|
33
|
+
export declare const resolveValueRef: (ref: ValueRef, context: ConditionContext) => unknown;
|
|
34
|
+
export declare const evaluateCondition: (condition: Condition, context: ConditionContext) => boolean;
|
|
35
|
+
/** Every node id a condition reads, for validation and dependency checks. */
|
|
36
|
+
export declare const conditionNodeIds: (condition: Condition) => string[];
|
|
37
|
+
/** Every section id a condition reads, so validation can catch a stale one. */
|
|
38
|
+
export declare const conditionSectionIds: (condition: Condition) => string[];
|
package/dist/engine.d.ts
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { type ConditionContext } from "./condition";
|
|
2
|
+
import type { AttemptSnapshot, BitEdge, BitflowDocument, BitflowMeta, BitNode, BitResult } from "./schema";
|
|
3
|
+
export declare const getNode: (doc: BitflowDocument, nodeId: string) => BitNode | undefined;
|
|
4
|
+
export declare const outgoingEdges: (doc: BitflowDocument, nodeId: string) => BitEdge[];
|
|
5
|
+
export declare const incomingEdges: (doc: BitflowDocument, nodeId: string) => BitEdge[];
|
|
6
|
+
/**
|
|
7
|
+
* Where a fresh attempt begins: the first registered `start` bit, else the
|
|
8
|
+
* first node nothing points at, else simply the first node. The fallbacks
|
|
9
|
+
* matter because tooling (the VS Code source view, validation) inspects
|
|
10
|
+
* documents without every bit package loaded.
|
|
11
|
+
*/
|
|
12
|
+
export declare const startNodeId: (doc: BitflowDocument) => string | undefined;
|
|
13
|
+
/**
|
|
14
|
+
* The nodes belonging to a pool, in document order.
|
|
15
|
+
*
|
|
16
|
+
* Membership is read off the nodes rather than held as a list on the pool, so
|
|
17
|
+
* a deleted step leaves nothing dangling behind it.
|
|
18
|
+
*/
|
|
19
|
+
export declare const poolMembers: (doc: BitflowDocument, poolId: string) => BitNode[];
|
|
20
|
+
/**
|
|
21
|
+
* Chooses `draw` members of each pool.
|
|
22
|
+
*
|
|
23
|
+
* `random` is injectable so a test can be deterministic; nothing else passes
|
|
24
|
+
* it. A pool asking for more members than it has simply gets all of them —
|
|
25
|
+
* validation warns the author, and a learner mid-assessment is the wrong place
|
|
26
|
+
* to enforce it.
|
|
27
|
+
*/
|
|
28
|
+
export declare const drawPools: (doc: BitflowDocument, random?: () => number) => Record<string, string[]>;
|
|
29
|
+
/**
|
|
30
|
+
* Whether this attempt walks through `nodeId` at all.
|
|
31
|
+
*
|
|
32
|
+
* Everything outside a pool is always active. A pool member is active only if
|
|
33
|
+
* this attempt drew it — and if the attempt has no draw recorded for its pool
|
|
34
|
+
* (an older snapshot, or a pool added since) it stays active, because hiding
|
|
35
|
+
* steps from a learner on the strength of missing data is the worse failure.
|
|
36
|
+
*/
|
|
37
|
+
export declare const isActiveNode: (snapshot: AttemptSnapshot, node: BitNode | undefined) => boolean;
|
|
38
|
+
export declare const isTerminalNode: (doc: BitflowDocument, nodeId: string) => boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Edges that leave a pool — source inside it, target outside.
|
|
41
|
+
*
|
|
42
|
+
* A shuffled pool navigates by its drawn order rather than by its internal
|
|
43
|
+
* wiring, so once the order runs out the only edges that still mean anything
|
|
44
|
+
* are the ones pointing out of it. Which member happens to carry them does not
|
|
45
|
+
* matter, and must not: after a shuffle the last member is a different one for
|
|
46
|
+
* every learner.
|
|
47
|
+
*
|
|
48
|
+
* There is no matching `poolEntryEdges`, because the way *in* needs no rule:
|
|
49
|
+
* every edge into a shuffled pool lands on whichever member the draw put first
|
|
50
|
+
* (`redirectIntoPool`), so any number of them behave the same. Only the way out
|
|
51
|
+
* is ambiguous, and `validateFlow` is where that gets said.
|
|
52
|
+
*/
|
|
53
|
+
export declare const poolExitEdges: (doc: BitflowDocument, poolId: string) => BitEdge[];
|
|
54
|
+
/**
|
|
55
|
+
* Where the learner goes next, and over which edge.
|
|
56
|
+
*
|
|
57
|
+
* The edge is part of the answer because `resetTarget` lives on it: the runtime
|
|
58
|
+
* has to know how it arrived somewhere to know what to clear on getting there.
|
|
59
|
+
*/
|
|
60
|
+
export type NextStep = {
|
|
61
|
+
nodeId: string;
|
|
62
|
+
/** Absent when the step came from a pool's drawn order rather than an edge. */
|
|
63
|
+
edge?: BitEdge;
|
|
64
|
+
};
|
|
65
|
+
export type NextStepOptions = {
|
|
66
|
+
/**
|
|
67
|
+
* Pool members this attempt did not draw. They are stepped over as though
|
|
68
|
+
* the graph did not contain them, which is what lets a pool be twenty
|
|
69
|
+
* ordinary nodes chained together rather than a construct of its own.
|
|
70
|
+
*/
|
|
71
|
+
isActive?: (node: BitNode) => boolean;
|
|
72
|
+
/**
|
|
73
|
+
* Pool id → the members this attempt drew, in the order to show them. Only
|
|
74
|
+
* consulted for a pool with `shuffle` on; `AttemptSnapshot.pools` is what
|
|
75
|
+
* goes here.
|
|
76
|
+
*/
|
|
77
|
+
order?: Record<string, string[]>;
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* The step that follows `currentId`, or `null` when the run is over.
|
|
81
|
+
*
|
|
82
|
+
* Pure: branching reads only the attempt context and the draw the attempt
|
|
83
|
+
* already recorded, so replaying the same inputs always picks the same path.
|
|
84
|
+
*/
|
|
85
|
+
export declare const nextStep: (doc: BitflowDocument, currentId: string, context: ConditionContext, options?: NextStepOptions) => NextStep | null;
|
|
86
|
+
/** `nextStep`, for callers that only need to know where. */
|
|
87
|
+
export declare const nextNodeId: (doc: BitflowDocument, currentId: string, context: ConditionContext, isActive?: (node: BitNode) => boolean, order?: Record<string, string[]>) => string | null;
|
|
88
|
+
/**
|
|
89
|
+
* The previous node, read off the attempt's own history rather than walked
|
|
90
|
+
* backwards through the graph. With conditions on edges a reverse walk cannot
|
|
91
|
+
* tell which branch was actually taken.
|
|
92
|
+
*/
|
|
93
|
+
export declare const previousNodeId: (snapshot: AttemptSnapshot) => string | null;
|
|
94
|
+
/** One row of the step list free navigation shows. */
|
|
95
|
+
export type VisitedStep = {
|
|
96
|
+
nodeId: string;
|
|
97
|
+
node: BitNode;
|
|
98
|
+
/** Where it sits in the list, 1-based. */
|
|
99
|
+
position: number;
|
|
100
|
+
current: boolean;
|
|
101
|
+
/** A task the learner has a result for. Always false for a content step. */
|
|
102
|
+
answered: boolean;
|
|
103
|
+
/** A task with no result yet — the thing a check-your-work list is for. */
|
|
104
|
+
outstanding: boolean;
|
|
105
|
+
section?: BitflowMeta["sections"][number];
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* The steps the learner has been to, oldest first and each one once.
|
|
109
|
+
*
|
|
110
|
+
* Read off the history rather than the graph: with conditions on edges the
|
|
111
|
+
* document cannot say which steps a particular learner saw. A step visited
|
|
112
|
+
* twice — a remediation loop — is one row, at the position it first appeared.
|
|
113
|
+
*/
|
|
114
|
+
export declare const visitedSteps: (doc: BitflowDocument, snapshot: AttemptSnapshot) => VisitedStep[];
|
|
115
|
+
/**
|
|
116
|
+
* Whether the learner may jump straight to `nodeId`.
|
|
117
|
+
*
|
|
118
|
+
* Only somewhere they have already been, and only when the flow allows free
|
|
119
|
+
* movement. Jumping forward is not on offer at any setting: which step comes
|
|
120
|
+
* next depends on answers that have not been given yet, so there is nothing
|
|
121
|
+
* truthful to jump to.
|
|
122
|
+
*/
|
|
123
|
+
export declare const canGoTo: (doc: BitflowDocument, snapshot: AttemptSnapshot, nodeId: string) => boolean;
|
|
124
|
+
/** The section a step belongs to, if the flow still declares one. */
|
|
125
|
+
export declare const sectionOf: (doc: BitflowDocument, node: BitNode | undefined) => BitflowMeta["sections"][number] | undefined;
|
|
126
|
+
/** The nodes in a section, in document order. */
|
|
127
|
+
export declare const sectionMembers: (doc: BitflowDocument, sectionId: string) => BitNode[];
|
|
128
|
+
/**
|
|
129
|
+
* Whether the learner may pass on this task.
|
|
130
|
+
*
|
|
131
|
+
* The task decides when it says so, otherwise the flow does. Read off the data
|
|
132
|
+
* rather than through the bit, so a bit never has to know the setting exists —
|
|
133
|
+
* the same bargain `weight` and `timeLimit` already make.
|
|
134
|
+
*/
|
|
135
|
+
export declare const canSkip: (doc: BitflowDocument, node: BitNode | undefined) => boolean;
|
|
136
|
+
/**
|
|
137
|
+
* Whether the learner may leave this step yet.
|
|
138
|
+
*
|
|
139
|
+
* Only a bit that declares `isComplete` can hold them, and only that bit knows
|
|
140
|
+
* why — the runtime disables Next and leaves the explanation to the step. A
|
|
141
|
+
* bit whose data does not parse is not held: refusing to let someone past a
|
|
142
|
+
* step that is broken anyway traps them in the assessment.
|
|
143
|
+
*/
|
|
144
|
+
export declare const canLeaveNode: (node: BitNode | undefined, answer: unknown) => boolean;
|
|
145
|
+
export declare const computeScore: (snapshot: AttemptSnapshot) => {
|
|
146
|
+
earned: number;
|
|
147
|
+
possible: number;
|
|
148
|
+
};
|
|
149
|
+
/**
|
|
150
|
+
* Everything a branch may read, gathered out of the attempt in one place.
|
|
151
|
+
*
|
|
152
|
+
* Takes the document as well as the snapshot because time limits, sections and
|
|
153
|
+
* the flow's own clock are properties of the assessment, not of the run.
|
|
154
|
+
*/
|
|
155
|
+
export declare const conditionContext: (doc: BitflowDocument, snapshot: AttemptSnapshot, now?: Date) => ConditionContext;
|
|
156
|
+
export declare const collectAnswers: (snapshot: AttemptSnapshot, nodeIds?: string[]) => Record<string, unknown>;
|
|
157
|
+
export declare const collectResults: (snapshot: AttemptSnapshot, nodeIds?: string[]) => Record<string, BitResult>;
|
|
158
|
+
/**
|
|
159
|
+
* Hops from `fromId` to the nearest (`optimistic`) or furthest (`pessimistic`)
|
|
160
|
+
* terminal node, ignoring conditions — this feeds the progress indicator, which
|
|
161
|
+
* must not depend on answers the learner has not given yet. Cycles are cut, and
|
|
162
|
+
* a node with no route to an end returns `Infinity`.
|
|
163
|
+
*/
|
|
164
|
+
export declare const distanceToEnd: (doc: BitflowDocument, fromId: string, mode?: "pessimistic" | "optimistic",
|
|
165
|
+
/**
|
|
166
|
+
* Undrawn pool members cost nothing to pass, so a progress bar counts the
|
|
167
|
+
* five steps this learner will take rather than the twenty in the file.
|
|
168
|
+
*/
|
|
169
|
+
isActive?: (node: BitNode) => boolean) => number;
|
|
170
|
+
/**
|
|
171
|
+
* Milliseconds spent on one task, including the stretch in progress.
|
|
172
|
+
*
|
|
173
|
+
* Time *spent*, not elapsed wall clock: `elapsedMs` only accumulates while the
|
|
174
|
+
* learner is actually on a node, so closing the tab pauses the clock. That is
|
|
175
|
+
* the only rule a snapshot can honour across a reload, and the fairer one.
|
|
176
|
+
*/
|
|
177
|
+
export declare const timeSpentOn: (snapshot: AttemptSnapshot, nodeId: string, now?: Date) => number;
|
|
178
|
+
/** Milliseconds spent across the whole attempt, on the same basis. */
|
|
179
|
+
export declare const timeSpent: (snapshot: AttemptSnapshot, now?: Date) => number;
|
|
180
|
+
/** The task's own limit in milliseconds, or `null` when it has none. */
|
|
181
|
+
export declare const taskTimeLimit: (node: BitNode | undefined) => number | null;
|
|
182
|
+
export type FlowProgress = {
|
|
183
|
+
/** Nodes the learner has already been shown, including the current one. */
|
|
184
|
+
visited: number;
|
|
185
|
+
/** Best-case hops still to go; `Infinity` when the graph has no route out. */
|
|
186
|
+
remaining: number;
|
|
187
|
+
/** `0`–`1`, or `1` once the attempt is finished. */
|
|
188
|
+
ratio: number;
|
|
189
|
+
};
|
|
190
|
+
export declare const flowProgress: (doc: BitflowDocument, snapshot: AttemptSnapshot) => FlowProgress;
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { $ZodIssue } from "zod/v4/core";
|
|
2
|
+
export declare const BITFLOW_ERROR_CODES: readonly ["INVALID_FLOW", "INVALID_ATTEMPT", "FLOW_ATTEMPT_MISMATCH", "UNKNOWN_BIT_TYPE", "LOAD_FAILED", "EVALUATION_FAILED"];
|
|
3
|
+
export type BitflowErrorCode = (typeof BITFLOW_ERROR_CODES)[number];
|
|
4
|
+
export type Diagnostic = {
|
|
5
|
+
/** Dot/bracket path into the offending document, e.g. `nodes.2.data.title`. */
|
|
6
|
+
path: string;
|
|
7
|
+
message: string;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* The payload of every `bitflow-error` event. A plain object rather than an
|
|
11
|
+
* `Error` subclass so it survives `structuredClone` and `JSON.stringify` on
|
|
12
|
+
* the way to a host that wants to log or display it.
|
|
13
|
+
*/
|
|
14
|
+
export type BitflowError = {
|
|
15
|
+
code: BitflowErrorCode;
|
|
16
|
+
message: string;
|
|
17
|
+
diagnostics?: Diagnostic[];
|
|
18
|
+
};
|
|
19
|
+
export declare const bitflowError: (code: BitflowErrorCode, message: string, diagnostics?: Diagnostic[]) => BitflowError;
|
|
20
|
+
/** Turns zod issues into the flat `{ path, message }` shape hosts receive. */
|
|
21
|
+
export declare const toDiagnostics: (issues: readonly $ZodIssue[]) => Diagnostic[];
|
|
22
|
+
export type Result<T> = {
|
|
23
|
+
ok: true;
|
|
24
|
+
value: T;
|
|
25
|
+
} | {
|
|
26
|
+
ok: false;
|
|
27
|
+
error: BitflowError;
|
|
28
|
+
};
|
package/dist/i18n.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type Locale } from "./schema";
|
|
2
|
+
export declare const DEFAULT_LOCALE: Locale;
|
|
3
|
+
/** Flat key → message. One JSON file per locale, per package. */
|
|
4
|
+
export type Catalog = Record<string, string>;
|
|
5
|
+
export type Catalogs = Partial<Record<Locale, Catalog>> & {
|
|
6
|
+
en: Catalog;
|
|
7
|
+
};
|
|
8
|
+
export declare const isLocale: (value: unknown) => value is Locale;
|
|
9
|
+
/**
|
|
10
|
+
* Picks the closest supported locale. Accepts full BCP-47 tags, so `"de-AT"`
|
|
11
|
+
* and `navigator.language` work without the caller trimming them first.
|
|
12
|
+
*/
|
|
13
|
+
export declare const resolveLocale: (requested?: string | null, fallback?: Locale) => Locale;
|
|
14
|
+
/**
|
|
15
|
+
* Substitutes `{name}` placeholders. Missing variables are left as-is rather
|
|
16
|
+
* than blanked, because a visible `{count}` in the UI is a far louder bug
|
|
17
|
+
* report than an empty gap.
|
|
18
|
+
*/
|
|
19
|
+
export declare const interpolate: (message: string, vars?: Record<string, string | number>) => string;
|
|
20
|
+
/**
|
|
21
|
+
* Looks a key up in `locale`, falling back to English and finally to the key
|
|
22
|
+
* itself — an untranslated string still renders something the reader can act
|
|
23
|
+
* on, which is what the old `@vocab` build step guaranteed at compile time.
|
|
24
|
+
*/
|
|
25
|
+
export declare const translate: (catalogs: Catalogs, key: string, locale: string | Locale | undefined, vars?: Record<string, string | number>) => string;
|
|
26
|
+
export type Translator = (key: string, vars?: Record<string, string | number>) => string;
|
|
27
|
+
/** Binds catalogs and a locale once, for components that translate a lot. */
|
|
28
|
+
export declare const createTranslator: (catalogs: Catalogs, locale?: string | Locale) => Translator;
|
|
29
|
+
export declare const formatDate: (value: Date | string | number, locale?: string | Locale, options?: Intl.DateTimeFormatOptions) => string;
|
|
30
|
+
export declare const formatDateTime: (value: Date | string | number, locale?: string | Locale) => string;
|
|
31
|
+
/**
|
|
32
|
+
* A duration as `1:04` or `2:01:04`. Learner-facing timings are minutes, not
|
|
33
|
+
* calendar units, so `Intl.DurationFormat` would be both heavier and wordier.
|
|
34
|
+
*/
|
|
35
|
+
export declare const formatDuration: (ms: number) => string;
|
package/dist/id.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ids only have to be unique inside one document or one attempt, so a UUID is
|
|
3
|
+
* plenty and needs no coordination. `crypto.randomUUID` is unavailable on
|
|
4
|
+
* insecure origins and in a few older embedders, hence the fallback.
|
|
5
|
+
*/
|
|
6
|
+
export declare const createId: (prefix?: string) => string;
|
package/dist/image.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* A picture, carried inside the document rather than linked from it.
|
|
4
|
+
*
|
|
5
|
+
* `.bitflow` files are moved around — mailed between teachers, dropped into a
|
|
6
|
+
* VLE, opened from a memory stick, taken offline — and a linked image breaks
|
|
7
|
+
* on every one of those journeys, usually in front of a class. Embedding costs
|
|
8
|
+
* file size, which the authoring form spends deliberately by scaling and
|
|
9
|
+
* re-encoding what it is given.
|
|
10
|
+
*/
|
|
11
|
+
export declare const ImageSchema: z.ZodObject<{
|
|
12
|
+
src: z.ZodDefault<z.ZodString>;
|
|
13
|
+
alt: z.ZodDefault<z.ZodString>;
|
|
14
|
+
}, z.core.$strip>;
|
|
15
|
+
export type Image = z.infer<typeof ImageSchema>;
|
|
16
|
+
/** Whether a source is embedded in the document rather than fetched. */
|
|
17
|
+
export declare const isEmbedded: (src: string) => boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Roughly how many bytes a `data:` URI costs in the saved file.
|
|
20
|
+
*
|
|
21
|
+
* The base64 payload is 4 characters per 3 bytes, and the JSON that carries it
|
|
22
|
+
* stores those characters one byte each — so the string length *is* the cost,
|
|
23
|
+
* which is the number an author needs when deciding whether a picture is worth
|
|
24
|
+
* it. Anything that is not a data URI costs only its own length.
|
|
25
|
+
*/
|
|
26
|
+
export declare const sourceBytes: (src: string) => number;
|
|
27
|
+
/** `1.4 MB`, for telling an author what a picture is costing them. */
|
|
28
|
+
export declare const formatBytes: (bytes: number) => string;
|
|
29
|
+
/**
|
|
30
|
+
* The size a picture is scaled to: never enlarged, never longer than
|
|
31
|
+
* `maxEdge` on its longest side.
|
|
32
|
+
*
|
|
33
|
+
* A phone photograph is 4000px across and a drag-and-drop background is shown
|
|
34
|
+
* at perhaps 800. Storing the original would put megabytes into every copy of
|
|
35
|
+
* the file to no visible effect.
|
|
36
|
+
*/
|
|
37
|
+
export declare const scaledSize: (width: number, height: number, maxEdge: number) => {
|
|
38
|
+
width: number;
|
|
39
|
+
height: number;
|
|
40
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
export * from "./
|
|
2
|
-
export * from "./
|
|
3
|
-
export * from "./
|
|
4
|
-
export * from "./
|
|
5
|
-
export * from "./
|
|
6
|
-
export * from "./
|
|
7
|
-
export * from "./
|
|
8
|
-
export * from "./
|
|
9
|
-
export * from "./
|
|
10
|
-
export * from "./
|
|
11
|
-
export * from "./
|
|
1
|
+
export * from "./attempt";
|
|
2
|
+
export * from "./image";
|
|
3
|
+
export * from "./condition";
|
|
4
|
+
export * from "./engine";
|
|
5
|
+
export * from "./errors";
|
|
6
|
+
export * from "./i18n";
|
|
7
|
+
export * from "./id";
|
|
8
|
+
export * from "./registry";
|
|
9
|
+
export * from "./score";
|
|
10
|
+
export * from "./schema";
|
|
11
|
+
export * from "./validate";
|
|
12
|
+
export * from "./styles";
|
|
13
|
+
export * from "./validateCondition";
|