Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | 19x 19x 19x 19x 19x 19x 19x 46x 5x 5x 6x 5x 12x 5x 19x 5x 5x 2x 5x 5x 5x 19x 132x 15x 27x 18x 18x 40x 39x 39x 1x 38x 38x 36x 31x 38x 16x 14x 14x 15x 14x 13x 19x 56x 18x 18x 16x 16x 21x 20x 15x 2x 1x 14x | import {
extractGroupsFromArgs,
extractProjectsFromArgs,
numericTargets,
} from '../profiles/scope-enforcer';
import type { ScopeConfig } from '../profiles/types';
import type { ToolRequirements } from '../types';
import { getNamespaceTier } from '../services/NamespaceTierDetector';
import { TIER_ORDER } from '../services/InstanceCapabilities';
import {
hasNamespaceSubscriptions,
runWithNamespaceTier,
} from '../services/namespace-tier-context';
import { canonicalProjectPath } from '../utils/api-path';
import { mapBounded } from '../utils/bounded-map';
import type { GitLabTier } from '../services/GitLabVersionDetector';
export interface NamespaceTarget {
path: string;
kind: 'project' | 'group' | 'either';
}
/** Stop optional lookups once one target makes a complete tier decision impossible. */
class UnknownSubscription extends Error {}
export function namespaceTargetsForScope(scope: ScopeConfig | undefined): NamespaceTarget[] {
if (!scope) return [];
const targets: NamespaceTarget[] = [];
for (const path of [scope.project, ...(scope.projects ?? [])])
if (path !== undefined) targets.push({ path, kind: 'project' });
for (const path of [scope.group, scope.namespace, ...(scope.groups ?? [])])
if (path !== undefined) targets.push({ path, kind: 'group' });
return targets;
}
/** Numeric namespace arguments retain the handler's group-first ambiguity. */
export function namespaceTargetsForArgs(args: Record<string, unknown>): NamespaceTarget[] {
const targets: NamespaceTarget[] = numericTargets(args).map(({ id, kind }) => ({
path: id,
kind,
}));
for (const path of extractProjectsFromArgs(args))
if (!/^\d+$/.test(path)) targets.push({ path, kind: 'project' });
for (const path of extractGroupsFromArgs(args))
if (!/^\d+$/.test(path)) targets.push({ path, kind: 'group' });
return targets;
}
export function needsNamespaceTier(requirements: ToolRequirements | undefined): boolean {
if (!requirements) return false;
return [
requirements.default,
...Object.values(requirements.actions ?? {}),
...Object.values(requirements.parameters ?? {}),
].some((req) => req.tier !== undefined && req.tier !== 'free');
}
function distinctRoots(targets: readonly NamespaceTarget[]): NamespaceTarget[] | null {
const unique = new Map<string, NamespaceTarget>();
for (const target of targets) {
// An opaque GID is resolved by its owning handler, not guessed to be a namespace.
if (target.path.startsWith('gid://')) return null;
let path: string;
try {
path = canonicalProjectPath(target.path);
} catch {
return null;
}
const slash = path.indexOf('/');
let key: string;
if (/^\d+$/.test(path)) key = `${target.kind}:${path}`;
else if (slash < 0) key = path;
else key = path.slice(0, slash);
unique.set(key, target);
}
return [...unique.values()];
}
function selectedTier(tiers: readonly GitLabTier[], union: boolean): GitLabTier | null {
let tier: GitLabTier | null = null;
for (const observation of tiers) {
if (!union && tier !== null && tier !== observation) return null;
if (tier === null || TIER_ORDER[observation] > TIER_ORDER[tier]) tier = observation;
}
return tier;
}
/** Catalogs expose the union; a call spanning different subscriptions defers to GitLab. */
export async function withNamespaceCapabilities<T>(
instanceUrl: string,
targets: readonly NamespaceTarget[],
union: boolean,
fn: () => T,
): Promise<Awaited<T>> {
if (!hasNamespaceSubscriptions(instanceUrl)) return await fn();
const unique = distinctRoots(targets);
if (unique === null) return await runWithNamespaceTier(instanceUrl, null, fn);
let observations;
try {
observations = await mapBounded(unique, 5, async (target) => {
const info = await getNamespaceTier(target.path, target.kind);
if (info.tier === null) throw new UnknownSubscription();
return info.tier;
});
} catch (error) {
if (!(error instanceof UnknownSubscription)) throw error;
return await runWithNamespaceTier(instanceUrl, null, fn);
}
return await runWithNamespaceTier(instanceUrl, selectedTier(observations, union), fn);
}
|