@jarenjs/core 0.73.0 → 0.83.2
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/ARCHITECTURE.md +4 -0
- package/README.md +15 -0
- package/dist/types/range/index.d.ts +81 -0
- package/dist/types/retry.d.ts +43 -0
- package/dist/types/schedule.d.ts +43 -0
- package/dist/types/search/config.d.ts +69 -0
- package/dist/types/search/index.d.ts +145 -0
- package/dist/types/search/vocabulary.d.ts +9 -0
- package/dist/types/virtual/index.d.ts +86 -0
- package/docs/SCHEDULING.md +62 -0
- package/docs/SEARCH.md +158 -0
- package/docs/VIRTUAL.md +40 -0
- package/package.json +22 -2
- package/src/range/index.js +125 -0
- package/src/retry.js +80 -0
- package/src/schedule.js +156 -0
- package/src/search/config.js +65 -0
- package/src/search/index.js +360 -0
- package/src/search/vocabulary.js +39 -0
- package/src/virtual/index.js +140 -0
package/ARCHITECTURE.md
CHANGED
|
@@ -1234,3 +1234,7 @@ export function isNumberType(data) {
|
|
|
1234
1234
|
When contributing, remember: this package is used by `@jarenjs/validate` and `@jarenjs/formats`. Changes here have downstream effects. Maintain backward compatibility, optimize for performance, and keep the API predictable.
|
|
1235
1235
|
|
|
1236
1236
|
For questions about the broader architecture, see the root [`ARCHITECTURE.md`](../../docs/ARCHITECTURE.md). For development workflows, see [`HOWTO.md`](../../docs/HOWTO.md).
|
|
1237
|
+
|
|
1238
|
+
`src/virtual/` owns DOM-free fixed and sparse measured collection geometry. It imports no presentation, app or storage owner; the visible component and injected coordinator live above it.
|
|
1239
|
+
|
|
1240
|
+
`src/search/` owns lexical definition compilation, postings, rank statistics and derived snapshots. The [search contract](docs/SEARCH.md) fixes tokenizer, scoring and tie semantics. `src/range/` owns the structural resident array provider; app re-exports it and linq injects it without importing an upper layer.
|
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# @jarenjs/core
|
|
2
2
|
|
|
3
|
+
Compose `core/virtual`, `core/range`, `core/search` and the shared retry/scheduling capabilities through the [public adoption recipes](../../docs/ADOPTION-EVIDENCE.md). The host supplies storage, workers and product policy; pure kernels own none of those resources.
|
|
4
|
+
|
|
3
5
|
The zero-dependency foundation of [Jaren](https://github.com/jklarenbeek/jarenjs). Everything the rest of the suite is built on lives here — type guards, Unicode-aware string handling, a large text-validation toolbox, number range helpers, fixed-point and vector math, the calendar kernel, the spatial kernel, the vector kernel, the interval kernel, the message-catalog compiler, unit/currency conversion and a finance library.
|
|
4
6
|
|
|
5
7
|
None of it depends on JSON Schema: every module can be used standalone in any JavaScript project.
|
|
@@ -202,6 +204,7 @@ Every subpath a consumer can import, derived from the manifest by
|
|
|
202
204
|
<!--fact:exports.core-->
|
|
203
205
|
| Import | Kind | Declarations |
|
|
204
206
|
|---|---|---|
|
|
207
|
+
| `@jarenjs/core/search` | JavaScript | declared |
|
|
205
208
|
| `@jarenjs/core` | JavaScript | declared |
|
|
206
209
|
| `@jarenjs/core/array` | JavaScript | declared |
|
|
207
210
|
| `@jarenjs/core/async` | JavaScript | declared |
|
|
@@ -296,8 +299,20 @@ Every subpath a consumer can import, derived from the manifest by
|
|
|
296
299
|
| `@jarenjs/core/convert/index` | JavaScript | declared |
|
|
297
300
|
| `@jarenjs/core/convert/registry` | JavaScript | declared |
|
|
298
301
|
| `@jarenjs/core/package.json` | metadata | — |
|
|
302
|
+
| `@jarenjs/core/virtual` | JavaScript | declared |
|
|
303
|
+
| `@jarenjs/core/range` | JavaScript | declared |
|
|
304
|
+
| `@jarenjs/core/retry` | JavaScript | declared |
|
|
305
|
+
| `@jarenjs/core/schedule` | JavaScript | declared |
|
|
299
306
|
<!--/fact-->
|
|
300
307
|
|
|
301
308
|
## Development
|
|
302
309
|
|
|
303
310
|
Unit tests live in `test/core/` at the repository root (`npm run test:core`). This package's internals are described in its own [ARCHITECTURE](./ARCHITECTURE.md) document, with per-module references under [docs/](./docs/) (`MATH`, `CONVERT`, `FINANCE`, `DATES`, `GEO`); see the repository [README](../../README.md) and [ARCHITECTURE](../../docs/ARCHITECTURE.md) for the monorepo picture, and the [ROADMAP](../../docs/ROADMAP.md) for planned work.
|
|
311
|
+
|
|
312
|
+
See [virtual geometry](docs/VIRTUAL.md) for opt-in constant-work fixed ranges and bounded sparse measured axes.
|
|
313
|
+
|
|
314
|
+
See [lexical search](docs/SEARCH.md) for the opt-in resident ranker and bounded source-derived snapshots. `@jarenjs/core/range` owns the structural resident array provider shared by app and linq.
|
|
315
|
+
|
|
316
|
+
[Bounded scheduling and retry](docs/SCHEDULING.md) describes `core/schedule` and
|
|
317
|
+
`core/retry`: fair per-scope admission, drained shutdown, shared attempt budgets
|
|
318
|
+
and explicit strict/AI/contract compatibility policies.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/** JSON wire byte cost. @param {any} value */
|
|
2
|
+
export declare const rangeBytes: (value: any) => number;
|
|
3
|
+
/** Echo request identity. @param {any} request */
|
|
4
|
+
export declare const rangeIdentity: (request: any) => {
|
|
5
|
+
[k: string]: any;
|
|
6
|
+
};
|
|
7
|
+
/** Validate finite request credits. @param {any} credits */
|
|
8
|
+
export declare const validRangeCredits: (credits: any) => boolean;
|
|
9
|
+
/** Validate a half-open logical range. @param {any} range */
|
|
10
|
+
export declare const validLogicalRange: (range: any) => any;
|
|
11
|
+
/**
|
|
12
|
+
* A resident-array provider. The immutable source copy and key index are reported separately
|
|
13
|
+
* from requested pages; virtual DOM does not make this resident source bounded by page credits.
|
|
14
|
+
* @param {any[]} initialRows @param {any} [options]
|
|
15
|
+
*/
|
|
16
|
+
export declare function createArrayRangeProvider(initialRows: any[], options?: any): {
|
|
17
|
+
query: any;
|
|
18
|
+
readonly snapshot: any;
|
|
19
|
+
capabilities: Readonly<{
|
|
20
|
+
seekIndex: boolean;
|
|
21
|
+
seekKey: true;
|
|
22
|
+
continuation: true;
|
|
23
|
+
exactTotal: boolean;
|
|
24
|
+
live: true;
|
|
25
|
+
completeExport: true;
|
|
26
|
+
}>;
|
|
27
|
+
indexOf(key: any): any;
|
|
28
|
+
stats(): {
|
|
29
|
+
rows: number;
|
|
30
|
+
bytes: number;
|
|
31
|
+
pages: number;
|
|
32
|
+
pending: number;
|
|
33
|
+
subscriptions: number;
|
|
34
|
+
};
|
|
35
|
+
replace(next: any, identity: any): void;
|
|
36
|
+
subscribe(fn: any): () => boolean;
|
|
37
|
+
request(input: any, signal: any): Promise<{
|
|
38
|
+
state: any;
|
|
39
|
+
reason: any;
|
|
40
|
+
used: {
|
|
41
|
+
pages: number;
|
|
42
|
+
rows: number;
|
|
43
|
+
bytes: number;
|
|
44
|
+
work: number;
|
|
45
|
+
};
|
|
46
|
+
} | {
|
|
47
|
+
state: string;
|
|
48
|
+
rows: any[];
|
|
49
|
+
keys: any[];
|
|
50
|
+
continuation: string | null;
|
|
51
|
+
total: {
|
|
52
|
+
kind: string;
|
|
53
|
+
value: number;
|
|
54
|
+
} | {
|
|
55
|
+
value?: undefined;
|
|
56
|
+
kind: string;
|
|
57
|
+
};
|
|
58
|
+
used: {
|
|
59
|
+
pages: number;
|
|
60
|
+
rows: number;
|
|
61
|
+
bytes: number;
|
|
62
|
+
work: number;
|
|
63
|
+
};
|
|
64
|
+
}>;
|
|
65
|
+
export(request: any, signal: any): AsyncGenerator<{
|
|
66
|
+
state: string;
|
|
67
|
+
rows: any[];
|
|
68
|
+
keys: any[];
|
|
69
|
+
query: any;
|
|
70
|
+
snapshot: any;
|
|
71
|
+
total?: undefined;
|
|
72
|
+
} | {
|
|
73
|
+
rows?: undefined;
|
|
74
|
+
keys?: undefined;
|
|
75
|
+
state: string;
|
|
76
|
+
total: number;
|
|
77
|
+
query: any;
|
|
78
|
+
snapshot: any;
|
|
79
|
+
}, void, unknown>;
|
|
80
|
+
dispose(): Promise<void>;
|
|
81
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/** Shared backoff arithmetic, abortable waits and an explicit dispatch budget. */
|
|
2
|
+
/**
|
|
3
|
+
* Calculate a delay; strict never shortens the server's minimum wait.
|
|
4
|
+
* Compatibility policies retain the published clients' distinct jitter shapes.
|
|
5
|
+
* @param {{ policy?: 'strict' | 'ai-compat' | 'contract-compat', baseMs?: number, maxMs?: number, random?: () => number }} options
|
|
6
|
+
* @param {number} attempt - failed attempt, counted from one
|
|
7
|
+
* @param {number} [retryAfterMs]
|
|
8
|
+
* @returns {number}
|
|
9
|
+
*/
|
|
10
|
+
export declare function backoffDelay(options: {
|
|
11
|
+
policy?: 'strict' | 'ai-compat' | 'contract-compat';
|
|
12
|
+
baseMs?: number;
|
|
13
|
+
maxMs?: number;
|
|
14
|
+
random?: () => number;
|
|
15
|
+
}, attempt: number, retryAfterMs?: number): number;
|
|
16
|
+
/**
|
|
17
|
+
* Parse only the selected header dialect. HTTP accepts seconds or HTTP-date;
|
|
18
|
+
* milliseconds accepts nonnegative numbers only; none ignores the header.
|
|
19
|
+
* @param {string | null | undefined} raw
|
|
20
|
+
* @param {{ dialect?: 'http' | 'milliseconds' | 'none', now?: number }} [options]
|
|
21
|
+
* @returns {number | undefined}
|
|
22
|
+
*/
|
|
23
|
+
export declare function parseRetryAfter(raw: string | null | undefined, { dialect, now }?: {
|
|
24
|
+
dialect?: 'http' | 'milliseconds' | 'none';
|
|
25
|
+
now?: number;
|
|
26
|
+
}): number | undefined;
|
|
27
|
+
/** @param {AbortSignal | null | undefined} signal @returns {any} */
|
|
28
|
+
export declare function abortError(signal: AbortSignal | null | undefined): any;
|
|
29
|
+
/** Abortable timer with listener cleanup on either settlement.
|
|
30
|
+
* @param {number} ms @param {AbortSignal} [signal] @returns {Promise<void>} */
|
|
31
|
+
export declare function sleep(ms: number, signal?: AbortSignal): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* A host-private total budget reused across SDK, workflow and job callbacks.
|
|
34
|
+
* The single-attempt transport takes a credit immediately before dispatch.
|
|
35
|
+
* @param {number} attempts
|
|
36
|
+
* @param {'safe-read' | 'provider-idempotent' | 'single-send'} [safety]
|
|
37
|
+
*/
|
|
38
|
+
export declare function createAttemptBudget(attempts: number, safety?: 'safe-read' | 'provider-idempotent' | 'single-send'): Readonly<{
|
|
39
|
+
safety: "provider-idempotent" | "safe-read" | "single-send";
|
|
40
|
+
readonly used: number;
|
|
41
|
+
readonly remaining: number;
|
|
42
|
+
take(): boolean;
|
|
43
|
+
}>;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export type ScheduleOptions = {
|
|
2
|
+
concurrency?: number;
|
|
3
|
+
maxQueue?: number;
|
|
4
|
+
spacingMs?: number;
|
|
5
|
+
maxScopes?: number;
|
|
6
|
+
now?: () => number;
|
|
7
|
+
sleep?: (ms: number, signal?: AbortSignal) => Promise<void>;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* @typedef {Object} ScheduleOptions
|
|
11
|
+
* @property {number} [concurrency]
|
|
12
|
+
* @property {number} [maxQueue]
|
|
13
|
+
* @property {number} [spacingMs]
|
|
14
|
+
* @property {number} [maxScopes]
|
|
15
|
+
* @property {() => number} [now]
|
|
16
|
+
* @property {(ms: number, signal?: AbortSignal) => Promise<void>} [sleep]
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Round-robin admission among ready scopes; FIFO inside each scope. Closing
|
|
20
|
+
* stops admission immediately and waits for admitted work, including workers
|
|
21
|
+
* which ignore cancellation. A host must keep resources until close settles.
|
|
22
|
+
* @param {ScheduleOptions} [options]
|
|
23
|
+
*/
|
|
24
|
+
export declare function createScheduler(options?: ScheduleOptions): Readonly<{
|
|
25
|
+
/** @template T @param {() => T | Promise<T>} worker
|
|
26
|
+
* @param {{ scope?: string, signal?: AbortSignal, deadline?: number }} [context]
|
|
27
|
+
* @returns {Promise<T>} */
|
|
28
|
+
run<T>(worker: () => T | Promise<T>, { scope, signal, deadline }?: {
|
|
29
|
+
scope?: string;
|
|
30
|
+
signal?: AbortSignal;
|
|
31
|
+
deadline?: number;
|
|
32
|
+
}): Promise<T>;
|
|
33
|
+
/** A server observation delays all following work in its scope.
|
|
34
|
+
* @param {string} scope @param {number} delayMs */
|
|
35
|
+
observe(scope: string, delayMs: number): void;
|
|
36
|
+
/** @returns {Promise<void>} */
|
|
37
|
+
close(): Promise<void>;
|
|
38
|
+
stats: () => {
|
|
39
|
+
active: number;
|
|
40
|
+
queued: number;
|
|
41
|
+
closed: boolean;
|
|
42
|
+
};
|
|
43
|
+
}>;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export type LexicalDefinition = {
|
|
2
|
+
version: number;
|
|
3
|
+
fields: string[];
|
|
4
|
+
profile?: string;
|
|
5
|
+
prefix?: boolean;
|
|
6
|
+
fuzzy?: number;
|
|
7
|
+
combineWith?: string;
|
|
8
|
+
boost?: Record<string, number>;
|
|
9
|
+
normalization?: string;
|
|
10
|
+
limits?: Partial<typeof SEARCH_LIMITS>;
|
|
11
|
+
};
|
|
12
|
+
/** @typedef {{version: number, fields: string[], profile?: string, prefix?: boolean,
|
|
13
|
+
* fuzzy?: number, combineWith?: string, boost?: Record<string, number>,
|
|
14
|
+
* normalization?: string, limits?: Partial<typeof SEARCH_LIMITS>}} LexicalDefinition */
|
|
15
|
+
/** Finite logical allocation and work credits, independent of output truncation. */
|
|
16
|
+
export declare const SEARCH_LIMITS: Readonly<{
|
|
17
|
+
maxDocuments: 100000;
|
|
18
|
+
maxSourceBytes: number;
|
|
19
|
+
maxIndexBytes: number;
|
|
20
|
+
maxTemporaryBytes: number;
|
|
21
|
+
maxTokens: 4000000;
|
|
22
|
+
maxPostings: 4000000;
|
|
23
|
+
maxVocabulary: 300000;
|
|
24
|
+
maxFieldBytes: 65536;
|
|
25
|
+
maxTokenLength: 128;
|
|
26
|
+
maxQueryBytes: 4096;
|
|
27
|
+
maxExpansions: 16384;
|
|
28
|
+
maxCandidates: 100000;
|
|
29
|
+
maxResults: 1000;
|
|
30
|
+
maxWork: 100000000;
|
|
31
|
+
maxBatchWork: 100000;
|
|
32
|
+
}>;
|
|
33
|
+
/** @param {LexicalDefinition} input */
|
|
34
|
+
export declare function lexicalConfig(input: LexicalDefinition): {
|
|
35
|
+
version: number;
|
|
36
|
+
fields: string[];
|
|
37
|
+
profile: string;
|
|
38
|
+
prefix: boolean;
|
|
39
|
+
fuzzy: number;
|
|
40
|
+
combineWith: string;
|
|
41
|
+
boost: {
|
|
42
|
+
[x: string]: number;
|
|
43
|
+
};
|
|
44
|
+
normalization: string;
|
|
45
|
+
limits: {
|
|
46
|
+
maxDocuments: 100000;
|
|
47
|
+
maxSourceBytes: number;
|
|
48
|
+
maxIndexBytes: number;
|
|
49
|
+
maxTemporaryBytes: number;
|
|
50
|
+
maxTokens: 4000000;
|
|
51
|
+
maxPostings: 4000000;
|
|
52
|
+
maxVocabulary: 300000;
|
|
53
|
+
maxFieldBytes: 65536;
|
|
54
|
+
maxTokenLength: 128;
|
|
55
|
+
maxQueryBytes: 4096;
|
|
56
|
+
maxExpansions: 16384;
|
|
57
|
+
maxCandidates: 100000;
|
|
58
|
+
maxResults: 1000;
|
|
59
|
+
maxWork: 100000000;
|
|
60
|
+
maxBatchWork: 100000;
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
/** Token boundaries intentionally preserve the oracle's tab and accent behavior.
|
|
64
|
+
* @param {string} value @returns {string[]} */
|
|
65
|
+
export declare function lexicalTokens(value: string): string[];
|
|
66
|
+
/** Banded Levenshtein in UTF-16 units, matching the named compatibility profile.
|
|
67
|
+
* @param {string} a @param {string} b @param {number} limit @param {() => void} step
|
|
68
|
+
* @param {Uint16Array} previous @param {Uint16Array} current */
|
|
69
|
+
export declare function lexicalDistance(a: string, b: string, limit: number, step: () => void, previous: Uint16Array, current: Uint16Array): number;
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
export { SEARCH_LIMITS } from './config.js';
|
|
2
|
+
export type LexicalDefinition = import('./config.js').LexicalDefinition;
|
|
3
|
+
export type LexicalIdentity = {
|
|
4
|
+
generation?: number;
|
|
5
|
+
sourceRevision?: string;
|
|
6
|
+
};
|
|
7
|
+
export type LexicalHit = {
|
|
8
|
+
id: string;
|
|
9
|
+
score: number;
|
|
10
|
+
};
|
|
11
|
+
/** @typedef {import('./config.js').LexicalDefinition} LexicalDefinition */
|
|
12
|
+
/** @typedef {{generation?:number, sourceRevision?:string}} LexicalIdentity */
|
|
13
|
+
/** @typedef {{id:string, score:number}} LexicalHit */
|
|
14
|
+
/** Compile a versioned definition once. Each create() owns an isolated resident index.
|
|
15
|
+
* @param {LexicalDefinition} definition */
|
|
16
|
+
export declare function compileLexical(definition: LexicalDefinition): Readonly<{
|
|
17
|
+
config: {
|
|
18
|
+
version: number;
|
|
19
|
+
fields: string[];
|
|
20
|
+
profile: string;
|
|
21
|
+
prefix: boolean;
|
|
22
|
+
fuzzy: number;
|
|
23
|
+
combineWith: string;
|
|
24
|
+
boost: {
|
|
25
|
+
[x: string]: number;
|
|
26
|
+
};
|
|
27
|
+
normalization: string;
|
|
28
|
+
limits: {
|
|
29
|
+
maxDocuments: 100000;
|
|
30
|
+
maxSourceBytes: number;
|
|
31
|
+
maxIndexBytes: number;
|
|
32
|
+
maxTemporaryBytes: number;
|
|
33
|
+
maxTokens: 4000000;
|
|
34
|
+
maxPostings: 4000000;
|
|
35
|
+
maxVocabulary: 300000;
|
|
36
|
+
maxFieldBytes: 65536;
|
|
37
|
+
maxTokenLength: 128;
|
|
38
|
+
maxQueryBytes: 4096;
|
|
39
|
+
maxExpansions: 16384;
|
|
40
|
+
maxCandidates: 100000;
|
|
41
|
+
maxResults: 1000;
|
|
42
|
+
maxWork: 100000000;
|
|
43
|
+
maxBatchWork: 100000;
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
identity: string;
|
|
47
|
+
create: () => {
|
|
48
|
+
config: any;
|
|
49
|
+
identity: any;
|
|
50
|
+
stats: () => {
|
|
51
|
+
documents: number;
|
|
52
|
+
vocabulary: number;
|
|
53
|
+
postings: number;
|
|
54
|
+
tokens: number;
|
|
55
|
+
sourceBytes: number;
|
|
56
|
+
indexBytes: number;
|
|
57
|
+
tombstones: number;
|
|
58
|
+
fieldLengths: any[];
|
|
59
|
+
generation: number;
|
|
60
|
+
sourceRevision: string;
|
|
61
|
+
disposed: boolean;
|
|
62
|
+
};
|
|
63
|
+
search: (text: string, options?: any) => {
|
|
64
|
+
state: any;
|
|
65
|
+
reason?: any;
|
|
66
|
+
generation: number;
|
|
67
|
+
sourceRevision: string;
|
|
68
|
+
identity: any;
|
|
69
|
+
};
|
|
70
|
+
/** Serialize a complete derived snapshot. The checksum detects corruption, not forgery.
|
|
71
|
+
* @returns {string} */
|
|
72
|
+
snapshot(): string;
|
|
73
|
+
/** Validate format, configuration and authoritative source before atomic publication.
|
|
74
|
+
* Recovery always rebuilds postings through the same bounded engine.
|
|
75
|
+
* @param {string} serialized @param {LexicalIdentity & {sourceRevision:string}} request */
|
|
76
|
+
restore(serialized: string, request: LexicalIdentity & {
|
|
77
|
+
sourceRevision: string;
|
|
78
|
+
}): {
|
|
79
|
+
state: any;
|
|
80
|
+
reason?: any;
|
|
81
|
+
generation: number;
|
|
82
|
+
sourceRevision: string;
|
|
83
|
+
identity: any;
|
|
84
|
+
};
|
|
85
|
+
/** Atomically build from authoritative text rows. @param {Iterable<any>} rows @param {LexicalIdentity} [request] */
|
|
86
|
+
rebuild: (rows: Iterable<any>, request?: LexicalIdentity) => {
|
|
87
|
+
state: any;
|
|
88
|
+
reason?: any;
|
|
89
|
+
generation: number;
|
|
90
|
+
sourceRevision: string;
|
|
91
|
+
identity: any;
|
|
92
|
+
};
|
|
93
|
+
/** Replace/remove by stable ID; unchanged text is a no-op. @param {{put?:Iterable<any>, remove?:Iterable<string>}} changes @param {LexicalIdentity} [request] */
|
|
94
|
+
update: (changes: {
|
|
95
|
+
put?: Iterable<any>;
|
|
96
|
+
remove?: Iterable<string>;
|
|
97
|
+
}, request?: LexicalIdentity) => {
|
|
98
|
+
state: any;
|
|
99
|
+
reason?: any;
|
|
100
|
+
generation: number;
|
|
101
|
+
sourceRevision: string;
|
|
102
|
+
identity: any;
|
|
103
|
+
};
|
|
104
|
+
/** Clear all postings without retaining tombstones. @param {LexicalIdentity} [request] */
|
|
105
|
+
clear: (request?: LexicalIdentity) => {
|
|
106
|
+
state: any;
|
|
107
|
+
reason?: any;
|
|
108
|
+
generation: number;
|
|
109
|
+
sourceRevision: string;
|
|
110
|
+
identity: any;
|
|
111
|
+
};
|
|
112
|
+
/** Cooperative atomic build. The host yields to its event loop and owns cancellation.
|
|
113
|
+
* @param {Iterable<any>} rows @param {LexicalIdentity & {yield:()=>Promise<void>, signal?:AbortSignal, onProgress?:(value:any)=>void}} request */
|
|
114
|
+
rebuildAsync: (rows: Iterable<any>, request: LexicalIdentity & {
|
|
115
|
+
yield: () => Promise<void>;
|
|
116
|
+
signal?: AbortSignal;
|
|
117
|
+
onProgress?: (value: any) => void;
|
|
118
|
+
}) => Promise<{
|
|
119
|
+
state: any;
|
|
120
|
+
reason?: any;
|
|
121
|
+
generation: number;
|
|
122
|
+
sourceRevision: string;
|
|
123
|
+
identity: any;
|
|
124
|
+
}>;
|
|
125
|
+
/** Cooperative atomic replacement/removal using the same staging engine.
|
|
126
|
+
* @param {{put?:Iterable<any>, remove?:Iterable<string>}} changes
|
|
127
|
+
* @param {LexicalIdentity & {yield:()=>Promise<void>, signal?:AbortSignal, onProgress?:(value:any)=>void}} request */
|
|
128
|
+
updateAsync: (changes: {
|
|
129
|
+
put?: Iterable<any>;
|
|
130
|
+
remove?: Iterable<string>;
|
|
131
|
+
}, request: LexicalIdentity & {
|
|
132
|
+
yield: () => Promise<void>;
|
|
133
|
+
signal?: AbortSignal;
|
|
134
|
+
onProgress?: (value: any) => void;
|
|
135
|
+
}) => Promise<{
|
|
136
|
+
state: any;
|
|
137
|
+
reason?: any;
|
|
138
|
+
generation: number;
|
|
139
|
+
sourceRevision: string;
|
|
140
|
+
identity: any;
|
|
141
|
+
}>;
|
|
142
|
+
/** Idempotently free every resident reference and fence staged work. */
|
|
143
|
+
dispose(): void;
|
|
144
|
+
};
|
|
145
|
+
}>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Compact traversal orders preserve the compatibility profile without retaining a trie. */
|
|
2
|
+
/** Build traversal ordinals from first occurrence in authoritative document order.
|
|
3
|
+
* The temporary compressed tree is released before publication; only two arrays of
|
|
4
|
+
* term references remain. Splitting a branch appends that branch at its parent.
|
|
5
|
+
* @param {Iterable<string>} words @param {()=>void} step */
|
|
6
|
+
export declare function lexicalVocabulary(words: Iterable<string>, step: () => void): Generator<undefined, {
|
|
7
|
+
forward: any[];
|
|
8
|
+
reverse: any[];
|
|
9
|
+
}, unknown>;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/** DOM-free virtual geometry. Work and retained state depend on the viewport and credits. */
|
|
2
|
+
/**
|
|
3
|
+
* A half-open fixed-size window, with no source access. Hidden viewports are empty.
|
|
4
|
+
* @param {{count:number, size:number, viewport:number, offset?:number, overscan?:number}} options
|
|
5
|
+
*/
|
|
6
|
+
export declare function fixedRange({ count, size, viewport, offset, overscan }: {
|
|
7
|
+
count: number;
|
|
8
|
+
size: number;
|
|
9
|
+
viewport: number;
|
|
10
|
+
offset?: number;
|
|
11
|
+
overscan?: number;
|
|
12
|
+
}): {
|
|
13
|
+
start: number;
|
|
14
|
+
end: number;
|
|
15
|
+
offset: number;
|
|
16
|
+
extent: number;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Sparse measured axis. Only credited measurements are retained; evicted sizes become estimates.
|
|
20
|
+
* Prefix summaries rebuild on measurement, never by enumerating logical items.
|
|
21
|
+
* @param {{count:number, estimateSize:number, maxMeasurements?:number, maxBytes?:number}} options
|
|
22
|
+
*/
|
|
23
|
+
export declare function createVirtualAxis({ count, estimateSize, maxMeasurements, maxBytes }: {
|
|
24
|
+
count: number;
|
|
25
|
+
estimateSize: number;
|
|
26
|
+
maxMeasurements?: number;
|
|
27
|
+
maxBytes?: number;
|
|
28
|
+
}): {
|
|
29
|
+
position: (index: any) => any;
|
|
30
|
+
size: (index: any) => any;
|
|
31
|
+
indexAt: (offset: any) => number;
|
|
32
|
+
extent(): any;
|
|
33
|
+
range({ offset, viewport, overscan }?: {
|
|
34
|
+
offset?: number | undefined;
|
|
35
|
+
overscan?: number | undefined;
|
|
36
|
+
viewport?: number | undefined;
|
|
37
|
+
}): {
|
|
38
|
+
start: number;
|
|
39
|
+
end: number;
|
|
40
|
+
offset: number;
|
|
41
|
+
extent: any;
|
|
42
|
+
};
|
|
43
|
+
measure(index: any, key: any, value: any): {
|
|
44
|
+
state: string;
|
|
45
|
+
reason: string;
|
|
46
|
+
} | {
|
|
47
|
+
reason?: undefined;
|
|
48
|
+
state: string;
|
|
49
|
+
};
|
|
50
|
+
anchor(offset: any, keyAt: any, query?: string): {
|
|
51
|
+
key: string;
|
|
52
|
+
index: number;
|
|
53
|
+
offset: number;
|
|
54
|
+
query: string;
|
|
55
|
+
} | null;
|
|
56
|
+
restore(anchor: any, indexOf: any, query?: string): {
|
|
57
|
+
state: string;
|
|
58
|
+
offset: any;
|
|
59
|
+
fallback: boolean;
|
|
60
|
+
};
|
|
61
|
+
update(next: any): void;
|
|
62
|
+
clear(): void;
|
|
63
|
+
stats(): {
|
|
64
|
+
measurements: number;
|
|
65
|
+
bytes: number;
|
|
66
|
+
summaries: number;
|
|
67
|
+
};
|
|
68
|
+
dispose(): void;
|
|
69
|
+
};
|
|
70
|
+
/** Add finite pinned indices to a window; pins count against the same mounted budget.
|
|
71
|
+
* @param {{start:number,end:number}} range @param {number[]} pins @param {number} count @param {number} budget */
|
|
72
|
+
export declare function virtualIndices(range: {
|
|
73
|
+
start: number;
|
|
74
|
+
end: number;
|
|
75
|
+
}, pins: number[], count: number, budget: number): {
|
|
76
|
+
state: string;
|
|
77
|
+
reason: string;
|
|
78
|
+
indices: never[];
|
|
79
|
+
} | {
|
|
80
|
+
reason?: undefined;
|
|
81
|
+
state: string;
|
|
82
|
+
indices: number[];
|
|
83
|
+
};
|
|
84
|
+
/** Normalize a browser RTL scroll offset at the DOM boundary. Modern engines use negative offsets.
|
|
85
|
+
* @param {number} value @param {number} maximum @param {'ltr'|'negative'|'reverse'|'default'} [mode] */
|
|
86
|
+
export declare function logicalScrollOffset(value: number, maximum: number, mode?: 'ltr' | 'negative' | 'reverse' | 'default'): number;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Bounded scheduling and retry policy
|
|
2
|
+
|
|
3
|
+
`@jarenjs/core/schedule` exports `createScheduler`. It owns admission, finite
|
|
4
|
+
concurrency and queues, fair service among ready scopes, start spacing and rate
|
|
5
|
+
observations. It does not perform network I/O or decide whether a request is safe
|
|
6
|
+
to retry. `@jarenjs/core/retry` owns shared delay arithmetic, header parsing,
|
|
7
|
+
abortable sleep and total dispatch credits.
|
|
8
|
+
|
|
9
|
+
```js
|
|
10
|
+
import { createScheduler } from '@jarenjs/core/schedule';
|
|
11
|
+
import { createAttemptBudget, backoffDelay } from '@jarenjs/core/retry';
|
|
12
|
+
|
|
13
|
+
const scheduler = createScheduler({ concurrency: 4, maxQueue: 64,
|
|
14
|
+
maxScopes: 256, spacingMs: 25 });
|
|
15
|
+
const budget = createAttemptBudget(3, 'safe-read');
|
|
16
|
+
await scheduler.run(() => {
|
|
17
|
+
if (!budget.take()) throw new Error('attempt budget exhausted');
|
|
18
|
+
return doOneAttempt();
|
|
19
|
+
}, { scope: 'origin/account', signal, deadline: Date.now() + 1000 });
|
|
20
|
+
await scheduler.close();
|
|
21
|
+
const delay = backoffDelay({ policy: 'strict', maxMs: 1000 }, 1, 10000);
|
|
22
|
+
// delay is 10000: the caller must wait that long or refuse the retry.
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The defaults are concurrency `4`, waiting queue `64`, retained rate scopes
|
|
26
|
+
`256`, and spacing `0` milliseconds. Bounds must be finite integers, with
|
|
27
|
+
positive concurrency/queue/scopes and nonnegative spacing. `now` and `sleep` are
|
|
28
|
+
injectable. `run(worker, {scope, signal, deadline})` returns the worker's value;
|
|
29
|
+
expired, cancelled or closed work never starts. Ready scopes take turns, and
|
|
30
|
+
each scope retains FIFO order. A waiting scope does not occupy a worker.
|
|
31
|
+
`observe(scope, delayMs)` delays subsequent starts in that scope by at least the
|
|
32
|
+
observation, including requests queued by other callers. Rate scopes are bounded
|
|
33
|
+
and expired records are discarded on activity.
|
|
34
|
+
|
|
35
|
+
`stats()` reports active and queued counts and closed state. `close()` stops
|
|
36
|
+
admission, rejects queued work and drains admitted work before resolving.
|
|
37
|
+
Workers which ignore cancellation can delay that resolution: resource owners
|
|
38
|
+
must wait, and transports must support abort for timely cleanup. Refusals are
|
|
39
|
+
errors with messages `closed`, `cancelled`, `deadline`, `queue-full` or
|
|
40
|
+
`scope-limit`; malformed options are `TypeError`s. A worker rejection preserves
|
|
41
|
+
its error and does not close the shared scheduler.
|
|
42
|
+
|
|
43
|
+
`backoffDelay({policy,baseMs,maxMs,random}, attempt, retryAfterMs)` uses an attempt
|
|
44
|
+
count starting at one. Strict exponential backoff uses full jitter up to its
|
|
45
|
+
cap, while an explicit server delay is honored without clamping. `ai-compat`
|
|
46
|
+
preserves the AI clients' half-to-full jitter and clamps server delays to the
|
|
47
|
+
cap. `contract-compat` preserves the HTTP client's additive integer jitter.
|
|
48
|
+
The published AI/contract attempt counts and wire semantics remain unchanged;
|
|
49
|
+
their transport-specific outcome loops are deliberate wrappers around this
|
|
50
|
+
shared arithmetic. Strict deadline refusal belongs to the provider executor.
|
|
51
|
+
|
|
52
|
+
`parseRetryAfter(raw, {dialect,now})` accepts HTTP seconds/date by default,
|
|
53
|
+
numeric milliseconds under `milliseconds`, or nothing under `none`.
|
|
54
|
+
`sleep(ms, signal)` removes its timer and listener on settlement. `abortError`
|
|
55
|
+
returns the signal's reason, or a platform-shaped AbortError.
|
|
56
|
+
|
|
57
|
+
`createAttemptBudget(totalAttempts, safety)` returns a private frozen capability
|
|
58
|
+
with `take()`, `used` and `remaining`. Categories are `safe-read`,
|
|
59
|
+
`provider-idempotent` and `single-send`; single-send caps the budget at one.
|
|
60
|
+
Reuse the same capability across outer SDK/workflow/job callbacks for the same
|
|
61
|
+
request. Disable SDK transport retries: one transport invocation must mean one
|
|
62
|
+
wire attempt. A method or timeout does not establish replay safety.
|