@bridge-ds/core 0.13.0 → 0.15.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,66 @@
1
+ import { GitHubClient, type RepoInfo } from './github-client';
2
+ /**
3
+ * - anonymous-public: not signed in, the repository is public (read-only Studio).
4
+ * - anonymous-unknown: not signed in, GitHub answers 404 (private or missing: GitHub does not say which).
5
+ * - no-access: signed in, GitHub answers 404 (no such repo, not a collaborator, or the App is not installed on it).
6
+ * - not-installed: signed in with explicit permission (triage or more) on a public repository, and the App's
7
+ * installations do not cover it: it is not installed there.
8
+ * - outside-contributor: signed in, public repository, read access only, and no App installation lists it. GitHub
9
+ * lists installations only where the user has explicit permission, so this may be a non-collaborator of a repo
10
+ * where Bridge is installed: never say "not installed" here. Browse only; ask an admin for access.
11
+ * - reader: pull or triage. Browse, comment, file suggestions.
12
+ * - writer: push or maintain. Plus direct changes.
13
+ * - admin: admin. Plus settings and protection.
14
+ */
15
+ export type RepoAccessState = 'anonymous-public' | 'anonymous-unknown' | 'no-access' | 'not-installed' | 'outside-contributor' | 'reader' | 'writer' | 'admin';
16
+ /** The viewer's permissions on a repository, as GET /repos returns them. */
17
+ export type RepoPermissions = NonNullable<RepoInfo['permissions']>;
18
+ export interface AccessFacts {
19
+ /** A token was sent. */
20
+ signedIn: boolean;
21
+ /** GET /repos answered 200 (false on 404). */
22
+ visible: boolean;
23
+ /**
24
+ * An installation of the App the user can reach covers the repository; null or undefined when not checked
25
+ * (personal token) or GitHub would not say.
26
+ */
27
+ installed?: boolean | null | undefined;
28
+ /** GET /repos said the repository is private. */
29
+ private?: boolean | undefined;
30
+ permissions?: RepoPermissions | undefined;
31
+ }
32
+ /** The access state from the facts (section 3.3 table). */
33
+ export declare function accessState(f: AccessFacts): RepoAccessState;
34
+ /**
35
+ * True when `state` grants at least what `min` grants: 'reader' (suggest, comment), 'writer' (direct changes),
36
+ * 'admin' (settings). The read-only states rank as 'anonymous-public'; the closed ones rank lowest.
37
+ */
38
+ export declare function accessAtLeast(state: RepoAccessState, min: 'anonymous-public' | 'reader' | 'writer' | 'admin'): boolean;
39
+ export interface RepoAccess {
40
+ state: RepoAccessState;
41
+ owner: string;
42
+ repo: string;
43
+ /** Undefined when GitHub did not show the repository. */
44
+ private: boolean | undefined;
45
+ defaultBranch: string | undefined;
46
+ permissions: RepoPermissions | undefined;
47
+ /** The App installation that gives the user this repository, when checked and found. */
48
+ installationId?: number | undefined;
49
+ /** With a Direct App client: whether that App is installed for the user on the repository (null when unknown). */
50
+ directInstalled?: boolean | null | undefined;
51
+ }
52
+ export interface ResolveAccessOptions {
53
+ /**
54
+ * The client's token is a GitHub App user-to-server token: check its installations (2 or 3 calls). Leave off for a
55
+ * personal token or anonymous reads; the state then comes from GET /repos alone.
56
+ */
57
+ app?: boolean;
58
+ /** A client with the Direct App's token, to learn whether that App is installed too (changes: "direct"). */
59
+ direct?: GitHubClient;
60
+ }
61
+ /**
62
+ * Reads what the client's token (or no token) can do on the client's repository. With `app`, the client's token must
63
+ * be a user token of the signing-in App (each App lists only its own installations). A 404 is a state, not an error;
64
+ * a rejected token (401) and an exhausted rate limit (429) are thrown for the caller to handle as today.
65
+ */
66
+ export declare function resolveRepoAccess(client: GitHubClient, opts?: ResolveAccessOptions): Promise<RepoAccess>;
@@ -0,0 +1,142 @@
1
+ import { type BridgeConfig, type ChangesMode } from './config';
2
+ import { type ScannedComponent } from './component-scan';
3
+ import { type ComponentSpecsFile, type SpecCoverage } from './component-spec';
4
+ import { type ContrastPairResult, type ContrastPairSpec } from './contrast-model';
5
+ import { type ProductConfig } from './products';
6
+ import { type RepoSource, type RepoSourceRef } from './repo-source';
7
+ import type { IntegrationsConfig } from './requests';
8
+ import type { Rights, VisualImpactMode } from './rights';
9
+ import { type TokenRows, type TokenRowTier } from './token-rows';
10
+ /** Paths used when bridge.config.json does not name them: where this repo kept them before the config did. */
11
+ export declare const REPO_MODEL_DEFAULTS: {
12
+ readonly tokensRoot: "packages/tokens/src";
13
+ readonly componentsDir: "packages/react/src/components";
14
+ readonly componentSpecs: "packages/react/component-specs.json";
15
+ /** Optional token usage notes (group -> sentence), relative to tokens.root, when tokens.usage is not set. */
16
+ readonly tokensUsage: "usage.json";
17
+ readonly repo: {
18
+ readonly owner: "peterbono";
19
+ readonly repo: "ai-design-system-demo";
20
+ readonly defaultBranch: "main";
21
+ };
22
+ };
23
+ /** The repository settings the site and Studio act on (roles, owners, mode), derived from bridge.config.json. */
24
+ export interface SiteRepo {
25
+ owner: string;
26
+ repo: string;
27
+ defaultBranch: string;
28
+ /** GitHub logins that count as design and tech owners for Tier 3 approvals. Empty: any two distinct approvers. */
29
+ owners: {
30
+ design: string[];
31
+ tech: string[];
32
+ };
33
+ /** Who may merge past missing approvals from Reviews, with a reason. `allowed` empty: no override. */
34
+ override: {
35
+ allowed: string[];
36
+ requireReason: boolean;
37
+ minReasonLength: number;
38
+ };
39
+ /** Which owner group approves design, approves tech and ships. null: not set. */
40
+ rights: Rights | null;
41
+ /** governance.soloOwnerCanApproveBoth: the only owner's approval covers design and tech. Default false. */
42
+ soloOwnerCanApproveBoth: boolean;
43
+ /** Visual before and after: on every pull request (auto) or when someone asks (on-demand, label visual-check). */
44
+ visualImpact: {
45
+ mode: VisualImpactMode;
46
+ };
47
+ /** Token root in the repo. */
48
+ tokensRoot: string;
49
+ /** Where component change requests go besides the GitHub issue. Empty: GitHub only. */
50
+ integrations: IntegrationsConfig;
51
+ /** The apps that consume the design system, the library being the default. */
52
+ products: ProductConfig[];
53
+ /** How changes reach the code: "suggest" (default) or "direct". */
54
+ changes: ChangesMode;
55
+ }
56
+ /**
57
+ * SiteRepo from a parsed config. `raw` (the file as parsed JSON) carries the older top-level keys loadConfig does not
58
+ * keep (`owner`, `defaultBranch`, `owners`); `fallback` names the repo when the config does not.
59
+ */
60
+ export declare function siteRepoFromConfig(config: BridgeConfig, raw?: unknown, fallback?: {
61
+ owner: string;
62
+ repo: string;
63
+ defaultBranch: string;
64
+ }): SiteRepo;
65
+ /** The config the model uses when the repo has no bridge.config.json (or an invalid one): the defaults above. */
66
+ export declare const defaultModelConfig: () => BridgeConfig;
67
+ /** bridge.config.json text -> config, parsed once. Never throws: problems are returned and the defaults stand in. */
68
+ export declare function parseModelConfig(text: string | null): {
69
+ config: BridgeConfig;
70
+ raw: unknown;
71
+ problems: string[];
72
+ };
73
+ export interface RepoModel {
74
+ ref: RepoSourceRef;
75
+ /** bridge.config.json as read, null when the repo has none. */
76
+ configText: string | null;
77
+ config: BridgeConfig;
78
+ site: SiteRepo;
79
+ /** What could not be read (invalid config, a docs.json that does not parse, an alias that does not resolve). */
80
+ problems: string[];
81
+ tokens: {
82
+ /** tokens.root, repo-relative. */
83
+ root: string;
84
+ /** Token file bodies keyed by path relative to tokens.root, as buildTokenSet and the token explorer read them. */
85
+ files: Record<string, string>;
86
+ rows: TokenRows;
87
+ /** Notes per token group (tokens.usage), null when the repo has none. */
88
+ usage: Record<string, string> | null;
89
+ };
90
+ contrast: {
91
+ /** Repo-relative checks file, undefined when the config names none. */
92
+ path: string | undefined;
93
+ specs: ContrastPairSpec[];
94
+ pairs: ContrastPairResult[];
95
+ };
96
+ /** Null when the scan was skipped (options.components false). */
97
+ components: {
98
+ dir: string;
99
+ /** Barrel file the families come from, when it exists. */
100
+ index: string | undefined;
101
+ families: {
102
+ name: string;
103
+ members: string[];
104
+ }[];
105
+ list: ScannedComponent[];
106
+ } | null;
107
+ specs: {
108
+ path: string;
109
+ /** Parsed component-specs.json, null when missing or of another version. */
110
+ file: ComponentSpecsFile | null;
111
+ /** Figma coverage entries, read even from an older file. */
112
+ coverage: SpecCoverage[];
113
+ };
114
+ }
115
+ export interface RepoModelOptions {
116
+ /** Scan components (3-4 files per component). Default true. */
117
+ components?: boolean;
118
+ /** Docs link of a token's CSS variable (the caller's routing), given its type, tier and token path. Default: none. */
119
+ href?: (cssVar: string, type: string, tier: TokenRowTier, path: string) => string | undefined;
120
+ /** Requests in flight. Default 8. */
121
+ concurrency?: number;
122
+ /**
123
+ * Hears how far the read has gone, in real file counts: once with every phase's total before the first body is
124
+ * read, then once per file settled. Phases run in order: tokens (token files, contrast checks, usage notes), then
125
+ * components (code, styles, stories, the index and the Figma specs), then docs (each component's docs file).
126
+ */
127
+ onProgress?: (progress: RepoModelProgress) => void;
128
+ }
129
+ /** The three reads of loadRepoModel, in the order they run. */
130
+ export type RepoModelPhase = 'tokens' | 'components' | 'docs';
131
+ export interface RepoModelProgress {
132
+ /** The phase being read. */
133
+ phase: RepoModelPhase;
134
+ /** Files of this phase settled so far, and in all (a phase with nothing to read reports 0 of 0). */
135
+ done: number;
136
+ total: number;
137
+ /** Across every phase: the bar of the whole read. `filesTotal` is known from the first report and never moves. */
138
+ filesDone: number;
139
+ filesTotal: number;
140
+ }
141
+ /** Reads a repo through `source` and computes its model. Never throws on repo content: see `problems`. */
142
+ export declare function loadRepoModel(source: RepoSource, options?: RepoModelOptions): Promise<RepoModel>;