@finbheara/archive-client 0.0.0-stage → 0.1.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.
@@ -0,0 +1,94 @@
1
+ import { type LandedFile } from "./assets.js";
2
+ import { type IndexFile } from "./indexes.js";
3
+ import { type Pin } from "./pin.js";
4
+ import { type OpenOptions, type Release, resolveTag } from "./release.js";
5
+ export interface CachedRelease {
6
+ tag: string;
7
+ cut: number | undefined;
8
+ source: string;
9
+ pinned: boolean;
10
+ bytes: number;
11
+ files: {
12
+ name: string;
13
+ bytes: number;
14
+ verified: LandedFile["verified"];
15
+ }[];
16
+ indexes: IndexFile[];
17
+ }
18
+ export interface ReleaseList {
19
+ root: string;
20
+ repo: string | null;
21
+ pin: Pin | null;
22
+ cached: CachedRelease[];
23
+ published?: string[];
24
+ }
25
+ export interface RemovalPlan {
26
+ dryRun: boolean;
27
+ remove: {
28
+ path: string;
29
+ bytes: number;
30
+ why: string;
31
+ }[];
32
+ keep: {
33
+ tag: string;
34
+ why: string;
35
+ }[];
36
+ bytes: number;
37
+ }
38
+ export declare class ReleaseManager {
39
+ private readonly opts;
40
+ readonly root: string;
41
+ constructor(opts?: OpenOptions);
42
+ cachedTags(): string[];
43
+ private cached;
44
+ list(o?: {
45
+ remote?: boolean;
46
+ }): Promise<ReleaseList>;
47
+ fetch(spec: string | number, o?: {
48
+ assets?: readonly string[];
49
+ }): Promise<Release>;
50
+ pin(spec: string | number): Promise<Pin>;
51
+ unpin(): boolean;
52
+ current(): {
53
+ pin: Pin | null;
54
+ cached: boolean;
55
+ };
56
+ config(patch: {
57
+ repo?: string;
58
+ }): {
59
+ repo?: string;
60
+ };
61
+ readConfig(): {
62
+ repo?: string;
63
+ };
64
+ add(dir: string, tag: string): Promise<Release>;
65
+ index(spec: string | number, names?: readonly string[], o?: {
66
+ force?: boolean;
67
+ }): Promise<{
68
+ tag: string;
69
+ built: {
70
+ name: string;
71
+ path: string;
72
+ }[];
73
+ }>;
74
+ private plan;
75
+ private planRemove;
76
+ private apply;
77
+ prune(o?: {
78
+ keep?: number;
79
+ dryRun?: boolean;
80
+ }): RemovalPlan;
81
+ remove(tag: string, o?: {
82
+ dryRun?: boolean;
83
+ }): RemovalPlan;
84
+ dropIndexes(tag?: string, o?: {
85
+ dryRun?: boolean;
86
+ }): RemovalPlan;
87
+ verify(tag: string): Promise<{
88
+ file: string;
89
+ want: string;
90
+ got: string;
91
+ }[]>;
92
+ }
93
+ export declare function releases(opts?: OpenOptions): ReleaseManager;
94
+ export { resolveTag };
@@ -0,0 +1,65 @@
1
+ import { type StaffRole } from "@finbheara/domain/noun-index";
2
+ import { type NameLevel } from "./dancers-names.js";
3
+ import type { IndexBuilder } from "./indexes.js";
4
+ import type { Release } from "./release.js";
5
+ export interface Taught {
6
+ school_id: string;
7
+ school: string | null;
8
+ name: string;
9
+ role: string | null;
10
+ credentials: string[];
11
+ years: number[];
12
+ from: number | null;
13
+ to: number | null;
14
+ former: boolean;
15
+ provisional: boolean;
16
+ }
17
+ export interface TdLink {
18
+ school_id: string;
19
+ school: string | null;
20
+ via: string;
21
+ captured: string;
22
+ }
23
+ export interface Registered {
24
+ year: number;
25
+ cat: string;
26
+ name_printed: string;
27
+ region: string;
28
+ region_code: string | null;
29
+ country: string;
30
+ }
31
+ export interface Sat {
32
+ kind: "majors" | "feis";
33
+ event: string | null;
34
+ year: number | null;
35
+ seats: number;
36
+ competitions: number;
37
+ }
38
+ export interface StaffPerson {
39
+ clrg: number | null;
40
+ judge_id: number | null;
41
+ nameLevel: NameLevel | "id";
42
+ names: string[];
43
+ taught: Taught[];
44
+ td_links: TdLink[];
45
+ register: Registered[];
46
+ sat: Sat[];
47
+ }
48
+ export interface StaffAnswer {
49
+ tag: string;
50
+ asked: string;
51
+ role: StaffRole;
52
+ arm: "unique" | "ambiguous" | "none";
53
+ people: StaffPerson[];
54
+ refused?: string;
55
+ }
56
+ export declare const staffIndex: IndexBuilder;
57
+ export declare class StaffFinder {
58
+ private readonly rel;
59
+ constructor(rel: Release);
60
+ teacher(asked: string): Promise<StaffAnswer>;
61
+ adjudicator(asked: string): Promise<StaffAnswer>;
62
+ private find;
63
+ private person;
64
+ private taughtWhere;
65
+ }
@@ -0,0 +1,8 @@
1
+ export interface Pin {
2
+ tag: string;
3
+ source: string;
4
+ }
5
+ export declare const pinPath: (root: string) => string;
6
+ export declare function readPin(root: string): Pin | null;
7
+ export declare function writePin(root: string, pin: Pin): void;
8
+ export declare function clearPin(root: string): boolean;
@@ -0,0 +1,60 @@
1
+ import type { CompAnswer, CompResolver } from "./comps.js";
2
+ import { type DancerAnswer, type DancerQuery } from "./dancers.js";
3
+ import type { Release } from "./release.js";
4
+ export interface RegistrationRow {
5
+ name: string;
6
+ order?: string;
7
+ school?: string;
8
+ codes: readonly string[];
9
+ feis: string;
10
+ year?: number;
11
+ titles?: Readonly<Record<string, string>>;
12
+ asOf?: string;
13
+ [k: string]: unknown;
14
+ }
15
+ export type DancerQueryLike = DancerQuery;
16
+ export interface DancerAnswerLike {
17
+ arm: "unique" | "ambiguous" | "none";
18
+ candidates: readonly unknown[];
19
+ [k: string]: unknown;
20
+ }
21
+ export interface DancerResolverLike {
22
+ resolve(q: DancerQuery): Promise<DancerAnswerLike | DancerAnswer> | DancerAnswerLike;
23
+ }
24
+ export interface DancerUnavailable {
25
+ arm: "unavailable";
26
+ why: string;
27
+ }
28
+ export interface ResolvedRegistration {
29
+ tag: string;
30
+ row: RegistrationRow;
31
+ comps: CompAnswer[];
32
+ age: {
33
+ band: string;
34
+ year: number | null;
35
+ code: string;
36
+ from: "comp" | "title";
37
+ } | null;
38
+ bands?: string[];
39
+ dancer: DancerAnswer | DancerAnswerLike | DancerUnavailable;
40
+ asked?: DancerQueryLike;
41
+ }
42
+ export declare function youngest<T extends {
43
+ age: string;
44
+ }>(answers: readonly T[]): T | undefined;
45
+ export interface ResolvedDancer {
46
+ tag: string;
47
+ asked: DancerQueryLike;
48
+ put: DancerQueryLike;
49
+ comp?: CompAnswer;
50
+ dancer: DancerAnswer | DancerAnswerLike | DancerUnavailable;
51
+ }
52
+ export declare function dancerResolverOf(rel: Release): DancerResolverLike;
53
+ export declare class RegistrationResolver {
54
+ private readonly rel;
55
+ private readonly comps;
56
+ private readonly dancers?;
57
+ constructor(rel: Release, comps: CompResolver, dancers?: DancerResolverLike | null | undefined);
58
+ dancer(q: DancerQueryLike): Promise<ResolvedDancer>;
59
+ resolve(rows: readonly RegistrationRow[]): Promise<ResolvedRegistration[]>;
60
+ }
@@ -0,0 +1,70 @@
1
+ import { Database } from "bun:sqlite";
2
+ import { type AssetPlan, type LandedFile, type Receipt, type ReleaseManifest } from "./assets.js";
3
+ import { CompResolver } from "./comps.js";
4
+ import { type ClientOptions } from "./config.js";
5
+ import { DancerResolver } from "./dancers.js";
6
+ import { FeisFinder } from "./feises.js";
7
+ import { type IndexBuilder } from "./indexes.js";
8
+ import { StaffFinder } from "./people.js";
9
+ import { type DancerResolverLike, RegistrationResolver } from "./registrations.js";
10
+ import { type Remote } from "./remote.js";
11
+ import { MajorsFinder, ResultFinder } from "./results.js";
12
+ import { type SchoolReaderChoice, SchoolResolver } from "./schools.js";
13
+ import { type ReleaseSpec } from "./tag.js";
14
+ export interface OpenOptions extends ClientOptions {
15
+ assets?: readonly string[];
16
+ remote?: Remote;
17
+ strict?: boolean;
18
+ keepCompressed?: boolean;
19
+ log?: (line: string) => void;
20
+ builders?: readonly IndexBuilder[];
21
+ schoolReader?: SchoolReaderChoice;
22
+ dancerResolver?: DancerResolverLike | null;
23
+ }
24
+ export declare function tagDir(root: string, tag: string): string;
25
+ export declare const receiptPath: (dir: string) => string;
26
+ export declare function readReceipt(dir: string): Receipt | null;
27
+ export declare function resolveTag(spec: string | number | ReleaseSpec, opts?: OpenOptions): Promise<string>;
28
+ export declare class Release {
29
+ readonly tag: string;
30
+ readonly cut: number | undefined;
31
+ readonly fraction: number;
32
+ readonly dir: string;
33
+ readonly root: string;
34
+ readonly manifest: ReleaseManifest;
35
+ readonly feises: FeisFinder;
36
+ readonly schools: SchoolResolver;
37
+ readonly dancers: DancerResolver;
38
+ readonly results: ResultFinder;
39
+ readonly majors: MajorsFinder;
40
+ readonly staff: StaffFinder;
41
+ readonly comps: CompResolver;
42
+ readonly registrations: RegistrationResolver;
43
+ private readonly opts;
44
+ private readonly handles;
45
+ private remoteAssets;
46
+ constructor(tag: string, root: string, manifest: ReleaseManifest, opts: OpenOptions);
47
+ receipt(): Receipt;
48
+ plan(asset: string): AssetPlan;
49
+ has(asset: string): boolean;
50
+ path(asset: string): string;
51
+ fetch(...assets: string[]): Promise<LandedFile[]>;
52
+ private listed;
53
+ private fetchOne;
54
+ private record;
55
+ db(asset: string): Database;
56
+ schoolReader(): SchoolReaderChoice;
57
+ builders(): readonly IndexBuilder[];
58
+ index(name: string, o?: {
59
+ force?: boolean;
60
+ }): Promise<string>;
61
+ indexDb(name: string): Promise<Database>;
62
+ close(): void;
63
+ [Symbol.dispose](): void;
64
+ }
65
+ export declare function land(raw: string, pub: {
66
+ name: string;
67
+ digest: string | null;
68
+ }, plan: AssetPlan, dest: string, opts: Pick<OpenOptions, "strict" | "keepCompressed">, log: (line: string) => void): Promise<LandedFile>;
69
+ export declare function openRelease(spec?: string | number, opts?: OpenOptions): Promise<Release>;
70
+ export declare function openCached(tag: string, opts?: OpenOptions): Release | null;
@@ -0,0 +1,16 @@
1
+ export interface RemoteAsset {
2
+ name: string;
3
+ size: number;
4
+ digest: string | null;
5
+ }
6
+ export interface Remote {
7
+ readonly name: string;
8
+ tags(repo: string): Promise<string[]>;
9
+ assets(repo: string, tag: string): Promise<RemoteAsset[]>;
10
+ download(repo: string, tag: string, name: string, dest: string): Promise<void>;
11
+ }
12
+ export declare const ghRemote: Remote;
13
+ export declare function httpsRemote(env?: Readonly<Record<string, string | undefined>>, fetchImpl?: typeof fetch): Remote;
14
+ export declare function fallbackRemote(first: Remote, second: Remote): Remote;
15
+ export declare function setRemote(r: Remote | null): Remote | null;
16
+ export declare function defaultRemote(): Remote;
@@ -0,0 +1,82 @@
1
+ import type { Release } from "./release.js";
2
+ export declare const FEIS_LOCAL_ID_FLOOR = 17179869184;
3
+ export interface ResultQuery {
4
+ dancer_id?: number;
5
+ feis?: string;
6
+ competition?: string;
7
+ school_id?: string;
8
+ year?: number;
9
+ limit?: number;
10
+ }
11
+ export interface ResultRow {
12
+ address: string;
13
+ competition: string;
14
+ event: string;
15
+ year: number | null;
16
+ tier: string;
17
+ title: string | null;
18
+ age: string | null;
19
+ category: string | null;
20
+ gender: string | null;
21
+ feis_level: number | null;
22
+ comp_no: string | null;
23
+ place: number | null;
24
+ place_printed: string;
25
+ competitors: number | null;
26
+ name_printed: string;
27
+ dancer_id: number | null;
28
+ dancer_scope: "per-release" | "stable" | null;
29
+ school_printed: string;
30
+ school_id: string | null;
31
+ yob: number | null;
32
+ qualifier: string | null;
33
+ }
34
+ export interface ResultAnswer {
35
+ tag: string;
36
+ db: string;
37
+ asked: ResultQuery;
38
+ rows: ResultRow[];
39
+ truncated: number;
40
+ }
41
+ export declare function queryResults(rel: Release, db: string, q: ResultQuery): ResultAnswer;
42
+ export declare class ResultFinder {
43
+ private readonly rel;
44
+ constructor(rel: Release);
45
+ query(q: ResultQuery): Promise<ResultAnswer>;
46
+ }
47
+ export interface MajorEvent {
48
+ event: string;
49
+ years: number[];
50
+ competitions: number;
51
+ rows: number;
52
+ }
53
+ export interface MajorCompetition {
54
+ competition: string;
55
+ event: string;
56
+ year: number | null;
57
+ tier: string;
58
+ comp_no: string | null;
59
+ title: string | null;
60
+ age: string | null;
61
+ gender: string | null;
62
+ category: string | null;
63
+ competitors: number | null;
64
+ rows: number;
65
+ }
66
+ export declare class MajorsFinder {
67
+ private readonly rel;
68
+ constructor(rel: Release);
69
+ private db;
70
+ events(): Promise<{
71
+ tag: string;
72
+ events: MajorEvent[];
73
+ }>;
74
+ competitions(q: {
75
+ event: string;
76
+ year?: number;
77
+ }): Promise<{
78
+ tag: string;
79
+ competitions: MajorCompetition[];
80
+ }>;
81
+ results(q: ResultQuery): Promise<ResultAnswer>;
82
+ }
@@ -0,0 +1,42 @@
1
+ import { type SchoolNameParser } from "@finbheara/domain/school";
2
+ import type { IndexBuilder } from "./indexes.js";
3
+ import type { Release } from "./release.js";
4
+ export type SchoolRung = "id" | "redirect" | "print" | "sn3" | "realWords";
5
+ export interface SchoolCandidate {
6
+ school_id: string;
7
+ display: string | null;
8
+ rows: number;
9
+ by: SchoolRung;
10
+ prints: string[];
11
+ regions: string[];
12
+ places: string[];
13
+ }
14
+ export interface SchoolAnswer {
15
+ tag: string;
16
+ asked: string;
17
+ arm: "unique" | "ambiguous" | "none";
18
+ candidates: SchoolCandidate[];
19
+ region?: {
20
+ asked: string;
21
+ narrowed: boolean;
22
+ };
23
+ redirected?: {
24
+ from: string;
25
+ to: string;
26
+ };
27
+ refused?: string;
28
+ }
29
+ export interface SchoolQuery {
30
+ region?: string;
31
+ }
32
+ export interface SchoolReaderChoice {
33
+ id: string;
34
+ reader: SchoolNameParser;
35
+ }
36
+ export declare const GENERIC_SCHOOL_READER: SchoolReaderChoice;
37
+ export declare const schoolsIndex: IndexBuilder;
38
+ export declare class SchoolResolver {
39
+ private readonly rel;
40
+ constructor(rel: Release);
41
+ resolve(asked: string, q?: SchoolQuery): Promise<SchoolAnswer>;
42
+ }
@@ -0,0 +1,24 @@
1
+ export declare const ARCHIVE_TAG: RegExp;
2
+ export interface ArchiveTag {
3
+ date: string;
4
+ cut?: number;
5
+ fraction?: number;
6
+ }
7
+ export declare function parseArchiveTag(tag: string): ArchiveTag | null;
8
+ export declare function renderArchiveTag(t: ArchiveTag): string;
9
+ export declare function cutOf(inputRelease: string | undefined): number | undefined;
10
+ export declare function compareTagsNewestFirst(a: string, b: string): number;
11
+ export type ReleaseSpec = {
12
+ kind: "latest";
13
+ } | {
14
+ kind: "pinned";
15
+ } | {
16
+ kind: "cut";
17
+ cut: number;
18
+ fraction: number;
19
+ } | {
20
+ kind: "tag";
21
+ tag: string;
22
+ };
23
+ export declare function parseReleaseSpec(spec: string | number): ReleaseSpec | string;
24
+ export declare function pickTag(tags: readonly string[], spec: ReleaseSpec): string | null;
package/package.json CHANGED
@@ -1,6 +1,53 @@
1
1
  {
2
- "name": "@finbheara/archive-client",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
2
+ "name": "@finbheara/archive-client",
3
+ "version": "0.1.0",
4
+ "description": "Open a versioned release of an Irish dance results archive: download, verify, decompress and cache it by tag, keep the cache, and resolve feises and schools against it",
5
+ "keywords": ["irish-dance", "results", "release", "cache", "sqlite"],
6
+ "license": "MIT",
7
+ "author": "Finbheara Systems",
8
+ "type": "module",
9
+ "sideEffects": false,
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/types/index.d.ts",
13
+ "default": "./dist/index.js"
14
+ },
15
+ "./tag": {
16
+ "types": "./dist/types/tag.d.ts",
17
+ "default": "./dist/tag.js"
18
+ },
19
+ "./config": {
20
+ "types": "./dist/types/config.d.ts",
21
+ "default": "./dist/config.js"
22
+ },
23
+ "./cli": {
24
+ "types": "./dist/types/cli.d.ts",
25
+ "default": "./dist/cli.js"
26
+ },
27
+ "./package.json": "./package.json"
28
+ },
29
+ "main": "./dist/index.js",
30
+ "types": "./dist/types/index.d.ts",
31
+ "bin": {
32
+ "idq": "./dist/cli.js"
33
+ },
34
+ "files": ["dist/*.js", "dist/chunks/*.js", "dist/types/**/*.d.ts", "README.md", "LICENSE"],
35
+ "engines": {
36
+ "bun": ">=1.4.2"
37
+ },
38
+ "publishConfig": {
39
+ "access": "public"
40
+ },
41
+ "scripts": {
42
+ "build": "bun scripts/build.ts",
43
+ "guard": "bun ../../tools/checks/archive-client-tarball.ts",
44
+ "prepublishOnly": "bun scripts/build.ts && bun ../../tools/checks/archive-client-tarball.ts"
45
+ },
46
+ "dependencies": {
47
+ "@finbheara/domain": "0.47.0",
48
+ "@finbheara/names": "0.22.0"
49
+ },
50
+ "devDependencies": {
51
+ "typescript": "7.0.2"
52
+ }
53
+ }