@adea-ai/plugins 4.0.0 → 4.0.6

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.
Files changed (147) hide show
  1. package/dist/agent-plugins-catalog.d.ts +2 -4
  2. package/dist/agent-plugins-catalog.js +42 -50
  3. package/dist/agent-plugins-catalog.js.map +1 -1
  4. package/dist/agent-plugins-schema.d.ts +8 -0
  5. package/dist/agent-plugins-schema.js +10 -1
  6. package/dist/agent-plugins-schema.js.map +1 -1
  7. package/dist/artifacts.d.ts +57 -0
  8. package/dist/artifacts.js +159 -0
  9. package/dist/artifacts.js.map +1 -0
  10. package/dist/build.d.ts +20 -0
  11. package/dist/build.js +103 -0
  12. package/dist/build.js.map +1 -0
  13. package/dist/capabilities.d.ts +7 -0
  14. package/dist/capabilities.js +116 -0
  15. package/dist/capabilities.js.map +1 -0
  16. package/dist/catalog-store.d.ts +76 -0
  17. package/dist/catalog-store.js +463 -0
  18. package/dist/catalog-store.js.map +1 -0
  19. package/dist/concurrency.d.ts +1 -0
  20. package/dist/concurrency.js +15 -0
  21. package/dist/concurrency.js.map +1 -0
  22. package/dist/consumer-index.d.ts +7 -29
  23. package/dist/consumer-index.js +24 -15
  24. package/dist/consumer-index.js.map +1 -1
  25. package/dist/digest.d.ts +13 -0
  26. package/dist/digest.js +47 -0
  27. package/dist/digest.js.map +1 -0
  28. package/dist/fs-atomic.d.ts +7 -0
  29. package/dist/fs-atomic.js +30 -0
  30. package/dist/fs-atomic.js.map +1 -0
  31. package/dist/harness.js +2 -1
  32. package/dist/harness.js.map +1 -1
  33. package/dist/icon-mirror.d.ts +5 -4
  34. package/dist/icon-mirror.js +73 -72
  35. package/dist/icon-mirror.js.map +1 -1
  36. package/dist/icons.d.ts +2 -2
  37. package/dist/icons.js +4 -12
  38. package/dist/icons.js.map +1 -1
  39. package/dist/index.d.ts +16 -309
  40. package/dist/index.js +12 -1900
  41. package/dist/index.js.map +1 -1
  42. package/dist/integrity-manifest.d.ts +43 -13
  43. package/dist/integrity-manifest.js +28 -17
  44. package/dist/integrity-manifest.js.map +1 -1
  45. package/dist/json-values.d.ts +3 -0
  46. package/dist/json-values.js +10 -0
  47. package/dist/json-values.js.map +1 -0
  48. package/dist/plugin-release.d.ts +38 -0
  49. package/dist/plugin-release.js +321 -0
  50. package/dist/plugin-release.js.map +1 -0
  51. package/dist/plugin-skips.d.ts +19 -0
  52. package/dist/plugin-skips.js +65 -0
  53. package/dist/plugin-skips.js.map +1 -0
  54. package/dist/policy.d.ts +13 -0
  55. package/dist/policy.js +26 -0
  56. package/dist/policy.js.map +1 -0
  57. package/dist/portable-catalog.d.ts +4 -4
  58. package/dist/portable-catalog.js +14 -126
  59. package/dist/portable-catalog.js.map +1 -1
  60. package/dist/portable-verify.d.ts +2 -0
  61. package/dist/portable-verify.js +68 -0
  62. package/dist/portable-verify.js.map +1 -0
  63. package/dist/publication.d.ts +12 -12
  64. package/dist/publication.js +31 -21
  65. package/dist/publication.js.map +1 -1
  66. package/dist/published-output.d.ts +17 -0
  67. package/dist/published-output.js +49 -0
  68. package/dist/published-output.js.map +1 -0
  69. package/dist/site-icons.d.ts +4 -3
  70. package/dist/site-icons.js +38 -11
  71. package/dist/site-icons.js.map +1 -1
  72. package/dist/snapshots.d.ts +39 -0
  73. package/dist/snapshots.js +238 -0
  74. package/dist/snapshots.js.map +1 -0
  75. package/dist/source-resolution.d.ts +28 -0
  76. package/dist/source-resolution.js +158 -0
  77. package/dist/source-resolution.js.map +1 -0
  78. package/dist/sources.d.ts +5 -1
  79. package/dist/sources.js +21 -27
  80. package/dist/sources.js.map +1 -1
  81. package/dist/synchronize.d.ts +44 -0
  82. package/dist/synchronize.js +118 -0
  83. package/dist/synchronize.js.map +1 -0
  84. package/dist/taxonomy.d.ts +23 -0
  85. package/dist/taxonomy.js +62 -0
  86. package/dist/taxonomy.js.map +1 -0
  87. package/dist/upstream.d.ts +42 -0
  88. package/dist/upstream.js +179 -0
  89. package/dist/upstream.js.map +1 -0
  90. package/dist/verify-artifacts.d.ts +36 -0
  91. package/dist/verify-artifacts.js +286 -0
  92. package/dist/verify-artifacts.js.map +1 -0
  93. package/native/build-provenance.txt +5 -5
  94. package/native/staged-reader-win32-arm64.node +0 -0
  95. package/native/staged-reader-win32-x64.node +0 -0
  96. package/package.json +3 -3
  97. package/src/agent-plugins-catalog.test.ts +2 -2
  98. package/src/agent-plugins-catalog.ts +46 -49
  99. package/src/agent-plugins-schema.ts +11 -1
  100. package/src/artifacts.test.ts +80 -0
  101. package/src/artifacts.ts +234 -0
  102. package/src/build.ts +131 -0
  103. package/src/capabilities.ts +153 -0
  104. package/src/catalog-store.ts +519 -0
  105. package/src/concurrency.ts +19 -0
  106. package/src/consumer-index.test.ts +147 -16
  107. package/src/consumer-index.ts +35 -43
  108. package/src/default-head.test.ts +143 -0
  109. package/src/digest.ts +55 -0
  110. package/src/fs-atomic.ts +32 -0
  111. package/src/harness.test.ts +4 -32
  112. package/src/harness.ts +2 -1
  113. package/src/icon-mirror.ts +78 -72
  114. package/src/icons.test.ts +0 -4
  115. package/src/icons.ts +4 -4
  116. package/src/index.test.ts +172 -46
  117. package/src/index.ts +58 -2562
  118. package/src/integrity-manifest.ts +41 -21
  119. package/src/json-values.ts +11 -0
  120. package/src/manifest-retry.test.ts +49 -0
  121. package/src/plugin-release.ts +457 -0
  122. package/src/plugin-skips.ts +110 -0
  123. package/src/policy.ts +39 -0
  124. package/src/portable-catalog.test.ts +0 -5
  125. package/src/portable-catalog.ts +16 -143
  126. package/src/portable-verify.ts +71 -0
  127. package/src/publication.test.ts +29 -1
  128. package/src/publication.ts +38 -22
  129. package/src/published-output.ts +60 -0
  130. package/src/site-icons.test.ts +73 -1
  131. package/src/site-icons.ts +31 -14
  132. package/src/snapshots.ts +287 -0
  133. package/src/source-config-sync.test.ts +84 -0
  134. package/src/source-digest.test.ts +61 -8
  135. package/src/source-resolution.ts +233 -0
  136. package/src/sources-json.test.ts +18 -2
  137. package/src/sources.ts +27 -33
  138. package/src/synchronize.ts +213 -0
  139. package/src/taxonomy.ts +87 -0
  140. package/src/upstream.ts +194 -0
  141. package/src/verify-artifacts.ts +365 -0
  142. package/src/write-artifacts.test.ts +374 -0
  143. package/dist/source-digest.d.ts +0 -2
  144. package/dist/source-digest.js +0 -12
  145. package/dist/source-digest.js.map +0 -1
  146. package/native/README.md +0 -24
  147. package/src/source-digest.ts +0 -14
@@ -0,0 +1,44 @@
1
+ import { type ConsumerIndexOptions, type GeneratedArtifacts } from './artifacts.js';
2
+ import { type BuildCatalogInput } from './build.js';
3
+ import type { SkippedPlugin } from './plugin-skips.js';
4
+ import type { CatalogPolicy } from './policy.js';
5
+ import type { Catalog, SourcesLock } from './schema.js';
6
+ import { type SnapshotLoader } from './snapshots.js';
7
+ import type { SourceConfig } from './sources.js';
8
+ export interface SyncInput extends ConsumerIndexOptions, Omit<BuildCatalogInput, 'resolvedSources' | 'snapshotLoader' | 'resolveExternalRefs'> {
9
+ readonly sources: readonly SourceConfig[];
10
+ readonly policy: CatalogPolicy;
11
+ readonly mode?: 'live' | 'offline';
12
+ readonly fixtureRoot?: string;
13
+ readonly sourceId?: string;
14
+ readonly dryRun?: boolean;
15
+ readonly existingLock?: SourcesLock;
16
+ readonly existingCatalog?: Catalog;
17
+ readonly fromLock?: SourcesLock;
18
+ readonly snapshotLoader?: SnapshotLoader;
19
+ /** Rebuild even when source pins are unchanged (used for explicit format migrations). */
20
+ readonly forceRebuild?: boolean;
21
+ }
22
+ export interface SyncResult {
23
+ readonly changed: boolean;
24
+ readonly dryRun: boolean;
25
+ readonly sourceHeads: readonly {
26
+ sourceId: string;
27
+ commitSha: string;
28
+ }[];
29
+ readonly catalog?: Catalog;
30
+ readonly lock?: SourcesLock;
31
+ readonly artifacts?: GeneratedArtifacts;
32
+ readonly changeReport: ChangeReport;
33
+ }
34
+ export interface ChangeReport {
35
+ readonly schemaVersion: 1;
36
+ readonly changedSources: readonly string[];
37
+ readonly addedPlugins: readonly string[];
38
+ readonly removedPlugins: readonly string[];
39
+ readonly changedPlugins: readonly string[];
40
+ readonly permissionSensitiveChanges: readonly string[];
41
+ readonly skippedPlugins: readonly SkippedPlugin[];
42
+ readonly contentResolution: 'complete' | 'complete-with-skips' | 'metadata-only';
43
+ }
44
+ export declare function synchronize(input: SyncInput): Promise<SyncResult>;
@@ -0,0 +1,118 @@
1
+ import { createArtifacts } from './artifacts.js';
2
+ import { buildCatalogInternal } from './build.js';
3
+ import { mapWithConcurrency } from './concurrency.js';
4
+ import { digest } from './digest.js';
5
+ import { FixtureSnapshotLoader, NetworkSnapshotLoader } from './snapshots.js';
6
+ import { createSourcesLock, resolveSource, sourceLockChanged } from './source-resolution.js';
7
+ import { verifyArtifacts } from './verify-artifacts.js';
8
+ export async function synchronize(input) {
9
+ const mode = input.mode ?? 'live';
10
+ const configs = input.sources.filter((source) => !input.sourceId || source.sourceId === input.sourceId);
11
+ if (configs.length === 0)
12
+ throw new Error(`SOURCE_NOT_FOUND: ${input.sourceId ?? 'none'}`);
13
+ const lockToUse = input.fromLock ?? input.existingLock;
14
+ const resolved = await mapWithConcurrency(configs, 4, (config) => resolveSource(config, mode, input.fixtureRoot, lockToUse, input.fromLock !== undefined));
15
+ const sourceHeads = resolved.map(({ config, commitSha }) => ({
16
+ sourceId: config.sourceId,
17
+ commitSha,
18
+ }));
19
+ const lock = createSourcesLock(resolved);
20
+ const unchanged = input.fromLock === undefined &&
21
+ input.forceRebuild !== true &&
22
+ input.existingLock !== undefined &&
23
+ resolved.length === input.existingLock.sources.length &&
24
+ lock.sources.every((source) => !sourceChanged(source, resolved.find((entry) => entry.config.sourceId === source.sourceId)?.config, input.existingLock, input.existingCatalog));
25
+ if (unchanged) {
26
+ return {
27
+ changed: false,
28
+ dryRun: input.dryRun ?? false,
29
+ sourceHeads,
30
+ changeReport: {
31
+ schemaVersion: 1,
32
+ changedSources: [],
33
+ addedPlugins: [],
34
+ removedPlugins: [],
35
+ changedPlugins: [],
36
+ permissionSensitiveChanges: [],
37
+ skippedPlugins: [],
38
+ contentResolution: input.metadataOnly ? 'metadata-only' : 'complete',
39
+ },
40
+ };
41
+ }
42
+ const { catalog, skippedPlugins } = await buildCatalogInternal({
43
+ ...input,
44
+ resolvedSources: resolved,
45
+ snapshotLoader: input.snapshotLoader ??
46
+ (mode === 'offline'
47
+ ? new FixtureSnapshotLoader(input.fixtureRoot ?? 'fixtures', configs)
48
+ : new NetworkSnapshotLoader(input.policy)),
49
+ resolveExternalRefs: mode === 'live',
50
+ });
51
+ // An offline build replays fixtures, so its curation findings are noise.
52
+ const artifacts = createArtifacts(catalog, lock, {
53
+ ...input,
54
+ curationDiagnostics: mode !== 'offline',
55
+ });
56
+ verifyArtifacts(artifacts);
57
+ const report = createChangeReport(catalog, lock, input.existingLock, input.existingCatalog, skippedPlugins);
58
+ if (input.policy.publishRequiresCompleteContent && input.metadataOnly) {
59
+ throw new Error('CATALOG_CONTENT_INCOMPLETE: publication requires complete content');
60
+ }
61
+ return {
62
+ changed: true,
63
+ dryRun: input.dryRun ?? false,
64
+ sourceHeads,
65
+ catalog,
66
+ lock,
67
+ artifacts,
68
+ changeReport: report,
69
+ };
70
+ }
71
+ /** Whether a source differs from the last published lock and catalog. */
72
+ function sourceChanged(source, current, existingLock, existingCatalog) {
73
+ const previous = existingLock?.sources.find((entry) => entry.sourceId === source.sourceId);
74
+ if (!previous || sourceLockChanged(previous, source))
75
+ return true;
76
+ if (!existingCatalog)
77
+ return false;
78
+ const prior = existingCatalog.sources.find((entry) => entry.sourceId === source.sourceId);
79
+ return (!prior ||
80
+ !current ||
81
+ prior.displayName !== current.displayName ||
82
+ prior.trustClassification !== current.trustClassification);
83
+ }
84
+ function createChangeReport(catalog, lock, existingLock, existingCatalog, skippedPlugins = []) {
85
+ const changedSources = lock.sources
86
+ .filter((source) => existingLock === undefined ||
87
+ sourceChanged(source, catalog.sources.find((entry) => entry.sourceId === source.sourceId), existingLock, existingCatalog))
88
+ .map((source) => source.sourceId);
89
+ const previousPlugins = new Map(existingCatalog?.plugins.map((plugin) => [plugin.pluginId, plugin]) ?? []);
90
+ const currentPlugins = new Map(catalog.plugins.map((plugin) => [plugin.pluginId, plugin]));
91
+ const addedPlugins = catalog.plugins
92
+ .filter((plugin) => !previousPlugins.has(plugin.pluginId))
93
+ .map((plugin) => plugin.pluginId);
94
+ const removedPlugins = [...previousPlugins.keys()].filter((pluginId) => !currentPlugins.has(pluginId));
95
+ const changedPlugins = catalog.plugins
96
+ .filter((plugin) => {
97
+ const previous = previousPlugins.get(plugin.pluginId);
98
+ return previous !== undefined && digest(previous) !== digest(plugin);
99
+ })
100
+ .map((plugin) => plugin.pluginId);
101
+ return {
102
+ schemaVersion: 1,
103
+ changedSources: changedSources.toSorted(),
104
+ addedPlugins: addedPlugins.toSorted(),
105
+ removedPlugins: removedPlugins.toSorted(),
106
+ changedPlugins: changedPlugins.toSorted(),
107
+ skippedPlugins,
108
+ permissionSensitiveChanges: catalog.plugins
109
+ .flatMap((plugin) => plugin.securityClassification.permissionSensitiveChanges.map((type) => `${plugin.pluginId}:${type}`))
110
+ .toSorted(),
111
+ contentResolution: skippedPlugins.length > 0
112
+ ? 'complete-with-skips'
113
+ : catalog.plugins.some((plugin) => plugin.securityClassification.contentResolution === 'metadata-only')
114
+ ? 'metadata-only'
115
+ : 'complete',
116
+ };
117
+ }
118
+ //# sourceMappingURL=synchronize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"synchronize.js","sourceRoot":"","sources":["../src/synchronize.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ export interface CategoryMap {
2
+ readonly aliases: Readonly<Record<string, string>>;
3
+ readonly fallback: string;
4
+ }
5
+ export interface ProductAliases {
6
+ readonly aliases: Readonly<Record<string, string>>;
7
+ }
8
+ export declare function stablePluginId(sourceId: string, upstreamName: string): string;
9
+ export declare function stableReleaseId(repositoryUrl: string, subdirectory: string, commitSha: string, contentDigest: string): string;
10
+ export declare function normalizeCategory(value: string, map: CategoryMap): string;
11
+ export declare function productGroupingKey(name: string, aliases: ProductAliases): string;
12
+ /**
13
+ * Orders plugins so each category's curated leading products come first, in
14
+ * the configured order. Consumers preview the head of each category, so this
15
+ * ordering decides what users see before expanding.
16
+ */
17
+ export declare function orderLeadingPlugins<T extends {
18
+ readonly plugins: readonly {
19
+ categories: readonly string[];
20
+ upstreamPluginName: string;
21
+ }[];
22
+ }>(catalog: T, leading?: Record<string, readonly string[]>): T;
23
+ export declare function slug(value: string): string;
@@ -0,0 +1,62 @@
1
+ import { contentId } from './digest.js';
2
+ export function stablePluginId(sourceId, upstreamName) {
3
+ return `plugin:${slug(sourceId)}:${slug(upstreamName)}`;
4
+ }
5
+ export function stableReleaseId(repositoryUrl, subdirectory, commitSha, contentDigest) {
6
+ return contentId('release', { repositoryUrl, subdirectory, commitSha, contentDigest });
7
+ }
8
+ export function normalizeCategory(value, map) {
9
+ const key = value.trim().toLocaleLowerCase();
10
+ return map.aliases[key] ?? (slug(key) || map.fallback);
11
+ }
12
+ export function productGroupingKey(name, aliases) {
13
+ const key = name.trim().toLocaleLowerCase();
14
+ return aliases.aliases[key] ?? slug(key);
15
+ }
16
+ /**
17
+ * Orders plugins so each category's curated leading products come first, in
18
+ * the configured order. Consumers preview the head of each category, so this
19
+ * ordering decides what users see before expanding.
20
+ */
21
+ export function orderLeadingPlugins(catalog, leading) {
22
+ if (!leading)
23
+ return catalog;
24
+ const leadRank = new Map();
25
+ for (const [category, names] of Object.entries(leading)) {
26
+ names.forEach((name, index) => {
27
+ const key = `${category}::${name}`;
28
+ if (!leadRank.has(key))
29
+ leadRank.set(key, index);
30
+ });
31
+ }
32
+ const rank = (plugin) => {
33
+ let best = Number.POSITIVE_INFINITY;
34
+ for (const category of plugin.categories) {
35
+ const value = leadRank.get(`${category}::${plugin.upstreamPluginName}`);
36
+ if (value !== undefined && value < best)
37
+ best = value;
38
+ }
39
+ return best;
40
+ };
41
+ return {
42
+ ...catalog,
43
+ plugins: catalog.plugins.toSorted((left, right) => rank(left) - rank(right)),
44
+ };
45
+ }
46
+ function trimSlugEdges(value) {
47
+ let start = 0;
48
+ let end = value.length;
49
+ while (start < end && value[start] === '-')
50
+ start += 1;
51
+ while (end > start && value[end - 1] === '-')
52
+ end -= 1;
53
+ return value.slice(start, end);
54
+ }
55
+ export function slug(value) {
56
+ const result = trimSlugEdges(value
57
+ .trim()
58
+ .toLocaleLowerCase()
59
+ .replace(/[^a-z0-9]+/g, '-')).slice(0, 128) || 'unknown';
60
+ return result.length < 2 ? `${result}-plugin` : result;
61
+ }
62
+ //# sourceMappingURL=taxonomy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"taxonomy.js","sourceRoot":"","sources":["../src/taxonomy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ import type { SiteIconFetcher } from './site-icons.js';
2
+ export declare function externalGitRef(ref: string | undefined): string;
3
+ export declare function resolveGitRef(repositoryUrl: string, ref: string): Promise<string>;
4
+ export declare function fetchUpstreamBytes(url: string, signal?: AbortSignal): Promise<Uint8Array>;
5
+ export declare function rawContentUrl(repositoryUrl: string, commitSha: string, path: string): string;
6
+ export declare function fetchText(url: string): Promise<string>;
7
+ /**
8
+ * Hosts that may receive the repository credential.
9
+ *
10
+ * Everything else is fetched anonymously. The token this build runs with
11
+ * authorises repository writes for the duration of the job, so a vendor
12
+ * homepage, its icon CDN or any other third party must never be handed it.
13
+ */
14
+ /** The hosts the network snapshot loader reads repositories from. */
15
+ export declare const GITHUB_REPOSITORY_HOSTS: readonly string[];
16
+ /**
17
+ * Request headers for one upstream URL.
18
+ *
19
+ * The credential and GitHub's media type are attached only for GitHub hosts.
20
+ * Sending them elsewhere is not merely a needless disclosure: `appwrite.io`
21
+ * answers a page carrying an `Authorization` header with HTTP 500, and a CDN
22
+ * asked for an image with `accept: application/vnd.github+json` can answer with
23
+ * bytes that are not the mark. A build that did this dropped marks it had
24
+ * already curated, and the curation verifier — which used its own anonymous
25
+ * headers — could not see it.
26
+ */
27
+ export declare function upstreamRequestHeaders(url: string): Record<string, string>;
28
+ /**
29
+ * Fetches vendor-site documents exactly as a live build does.
30
+ *
31
+ * Shared with the curation verifier so both ask a vendor the same question: a
32
+ * verifier with its own headers reports sites healthy that the build then fails
33
+ * to resolve.
34
+ *
35
+ * `deadline` optionally bounds one product's whole resolution. The per-request
36
+ * ceiling is always created fresh inside each fetch, so a caller that passes a
37
+ * deadline — or shares one — can never hand later requests an already-expired
38
+ * signal.
39
+ */
40
+ export declare function createSiteIconFetcher(deadline?: AbortSignal): SiteIconFetcher;
41
+ export declare const SITE_FETCH_TIMEOUT_MS = 15000;
42
+ export declare function fetchUpstream(url: string, init: RequestInit): Promise<Response>;
@@ -0,0 +1,179 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { setTimeout as sleep } from 'node:timers/promises';
3
+ import { canonicalRepositoryUrl } from './sources.js';
4
+ export function externalGitRef(ref) {
5
+ if (ref === undefined)
6
+ return 'HEAD';
7
+ return ref.startsWith('refs/') ? ref : `refs/heads/${ref}`;
8
+ }
9
+ export async function resolveGitRef(repositoryUrl, ref) {
10
+ const peeled = ref.startsWith('refs/tags/') && !ref.endsWith('^{}') ? `${ref}^{}` : undefined;
11
+ const result = spawn('git', ['ls-remote', canonicalRepositoryUrl(repositoryUrl), ref, ...(peeled ? [peeled] : [])], {
12
+ stdio: ['ignore', 'pipe', 'pipe'],
13
+ });
14
+ const [stdout, stderr, exitCode] = await Promise.all([
15
+ new Promise((resolveOutput, reject) => {
16
+ const chunks = [];
17
+ result.stdout?.on('data', (chunk) => chunks.push(chunk));
18
+ result.stdout?.on('error', reject);
19
+ result.stdout?.on('end', () => resolveOutput(Buffer.concat(chunks).toString('utf8')));
20
+ }),
21
+ new Promise((resolveError) => {
22
+ const chunks = [];
23
+ result.stderr?.on('data', (chunk) => chunks.push(chunk));
24
+ result.stderr?.on('error', () => resolveError(''));
25
+ result.stderr?.on('end', () => resolveError(Buffer.concat(chunks).toString('utf8')));
26
+ }),
27
+ new Promise((resolveExit, reject) => {
28
+ result.on('error', reject);
29
+ result.on('close', (code) => resolveExit(code ?? 1));
30
+ }),
31
+ ]);
32
+ if (exitCode !== 0)
33
+ throw new Error(`GIT_REF_LOOKUP_FAILED: ${repositoryUrl}:${ref}:${stderr.trim()}`);
34
+ const rows = stdout
35
+ .trim()
36
+ .split('\n')
37
+ .map((line) => line.split(/\s+/));
38
+ const sha = (peeled && rows.find((row) => row[1] === peeled)?.[0]) ??
39
+ rows.find((row) => row[1] === ref)?.[0];
40
+ if (!sha || !/^[a-f0-9]{40}$/.test(sha))
41
+ throw new Error(`GIT_REF_NOT_FOUND: ${repositoryUrl}:${ref}`);
42
+ return sha;
43
+ }
44
+ export async function fetchUpstreamBytes(url, signal) {
45
+ const response = await fetchUpstream(url, {
46
+ headers: upstreamRequestHeaders(url),
47
+ ...(signal ? { signal } : {}),
48
+ });
49
+ if (!response.ok)
50
+ throw new Error(`HTTP_FETCH_FAILED: ${response.status}: ${url}`);
51
+ return new Uint8Array(await response.arrayBuffer());
52
+ }
53
+ export function rawContentUrl(repositoryUrl, commitSha, path) {
54
+ const parsed = new URL(canonicalRepositoryUrl(repositoryUrl));
55
+ return `https://raw.githubusercontent.com${parsed.pathname}/${commitSha}/${path.split('/').map(encodeURIComponent).join('/')}`;
56
+ }
57
+ export async function fetchText(url) {
58
+ const response = await fetchUpstream(url, { headers: upstreamRequestHeaders(url) });
59
+ if (!response.ok)
60
+ throw new Error(`HTTP_FETCH_FAILED: ${response.status}:${url}`);
61
+ return response.text();
62
+ }
63
+ const UPSTREAM_USER_AGENT = 'agent-hq-plugin-marketplace';
64
+ /**
65
+ * Hosts that may receive the repository credential.
66
+ *
67
+ * Everything else is fetched anonymously. The token this build runs with
68
+ * authorises repository writes for the duration of the job, so a vendor
69
+ * homepage, its icon CDN or any other third party must never be handed it.
70
+ */
71
+ /** The hosts the network snapshot loader reads repositories from. */
72
+ export const GITHUB_REPOSITORY_HOSTS = ['github.com', 'www.github.com'];
73
+ const GITHUB_CREDENTIAL_HOSTS = /(^|\.)(github\.com|githubusercontent\.com)$/;
74
+ /**
75
+ * Request headers for one upstream URL.
76
+ *
77
+ * The credential and GitHub's media type are attached only for GitHub hosts.
78
+ * Sending them elsewhere is not merely a needless disclosure: `appwrite.io`
79
+ * answers a page carrying an `Authorization` header with HTTP 500, and a CDN
80
+ * asked for an image with `accept: application/vnd.github+json` can answer with
81
+ * bytes that are not the mark. A build that did this dropped marks it had
82
+ * already curated, and the curation verifier — which used its own anonymous
83
+ * headers — could not see it.
84
+ */
85
+ export function upstreamRequestHeaders(url) {
86
+ const anonymous = { 'user-agent': UPSTREAM_USER_AGENT };
87
+ let host;
88
+ try {
89
+ host = new URL(url).hostname.toLowerCase();
90
+ }
91
+ catch {
92
+ return anonymous;
93
+ }
94
+ const token = process.env.GITHUB_TOKEN ?? process.env.GH_TOKEN;
95
+ if (!token || !GITHUB_CREDENTIAL_HOSTS.test(host))
96
+ return anonymous;
97
+ return {
98
+ accept: 'application/vnd.github+json',
99
+ authorization: `Bearer ${token}`,
100
+ 'user-agent': UPSTREAM_USER_AGENT,
101
+ };
102
+ }
103
+ /**
104
+ * Fetches vendor-site documents exactly as a live build does.
105
+ *
106
+ * Shared with the curation verifier so both ask a vendor the same question: a
107
+ * verifier with its own headers reports sites healthy that the build then fails
108
+ * to resolve.
109
+ *
110
+ * `deadline` optionally bounds one product's whole resolution. The per-request
111
+ * ceiling is always created fresh inside each fetch, so a caller that passes a
112
+ * deadline — or shares one — can never hand later requests an already-expired
113
+ * signal.
114
+ */
115
+ export function createSiteIconFetcher(deadline) {
116
+ const bounded = () => {
117
+ const ceiling = AbortSignal.timeout(SITE_FETCH_TIMEOUT_MS);
118
+ return deadline ? AbortSignal.any([deadline, ceiling]) : ceiling;
119
+ };
120
+ return {
121
+ fetchText: async (url) => new TextDecoder().decode(await fetchUpstreamBytes(url, bounded())),
122
+ fetchBytes: (url) => fetchUpstreamBytes(url, bounded()),
123
+ };
124
+ }
125
+ export const SITE_FETCH_TIMEOUT_MS = 15_000;
126
+ const UPSTREAM_FETCH_MAX_ATTEMPTS = 3;
127
+ const UPSTREAM_FETCH_BASE_DELAY_MS = 1000;
128
+ const UPSTREAM_FETCH_MAX_DELAY_MS = 30000;
129
+ function upstreamRetryDelayMs(attempt, response) {
130
+ const retryAfter = response?.headers.get('retry-after');
131
+ if (retryAfter !== null && retryAfter !== undefined) {
132
+ const seconds = Number(retryAfter);
133
+ if (Number.isFinite(seconds) && seconds >= 0)
134
+ return Math.min(seconds * 1000, UPSTREAM_FETCH_MAX_DELAY_MS);
135
+ const date = Date.parse(retryAfter);
136
+ if (!Number.isNaN(date))
137
+ return Math.min(Math.max(date - Date.now(), 0), UPSTREAM_FETCH_MAX_DELAY_MS);
138
+ }
139
+ return Math.min(UPSTREAM_FETCH_BASE_DELAY_MS * 2 ** attempt, UPSTREAM_FETCH_MAX_DELAY_MS);
140
+ }
141
+ function isRateLimitedUpstream(response) {
142
+ return (response.headers.get('x-ratelimit-remaining') === '0' ||
143
+ response.headers.get('retry-after') !== null);
144
+ }
145
+ function isRetryableUpstreamStatus(status, response) {
146
+ if (status === 429)
147
+ return true;
148
+ if (status >= 500)
149
+ return true;
150
+ if (status === 403 && response !== undefined && isRateLimitedUpstream(response))
151
+ return true;
152
+ return false;
153
+ }
154
+ export async function fetchUpstream(url, init) {
155
+ let attempt = 0;
156
+ for (;;) {
157
+ let response;
158
+ try {
159
+ response = await fetch(url, init);
160
+ }
161
+ catch (error) {
162
+ if (init.signal?.aborted || attempt >= UPSTREAM_FETCH_MAX_ATTEMPTS - 1)
163
+ throw error;
164
+ await sleep(upstreamRetryDelayMs(attempt), undefined, { signal: init.signal ?? undefined });
165
+ attempt += 1;
166
+ continue;
167
+ }
168
+ if (response.ok ||
169
+ !isRetryableUpstreamStatus(response.status, response) ||
170
+ attempt >= UPSTREAM_FETCH_MAX_ATTEMPTS - 1)
171
+ return response;
172
+ await response.body?.cancel().catch(() => { });
173
+ await sleep(upstreamRetryDelayMs(attempt, response), undefined, {
174
+ signal: init.signal ?? undefined,
175
+ });
176
+ attempt += 1;
177
+ }
178
+ }
179
+ //# sourceMappingURL=upstream.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upstream.js","sourceRoot":"","sources":["../src/upstream.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ import type { GeneratedArtifacts } from './artifacts.js';
2
+ import { type ConsumerCategory, type ConsumerIndex, type ConsumerProduct, type LeadingDiagnostic } from './consumer-index.js';
3
+ import { type CatalogPolicy } from './policy.js';
4
+ import { type Catalog } from './schema.js';
5
+ export interface ConsumerIndexVerification {
6
+ readonly hasConsumerIndex: boolean;
7
+ readonly diagnostics: readonly LeadingDiagnostic[];
8
+ readonly counts?: ConsumerIndex['counts'];
9
+ readonly topCount?: number;
10
+ readonly products?: Readonly<Record<string, ConsumerProduct>>;
11
+ readonly categories?: readonly ConsumerCategory[];
12
+ /** Shards the published integrity file set must carry for this index. */
13
+ readonly shards: readonly ShardArtifact[];
14
+ }
15
+ export interface ShardArtifact {
16
+ readonly name: string;
17
+ readonly kind: 'index' | 'shelf' | 'list';
18
+ readonly category?: string;
19
+ }
20
+ export declare function verifyArtifacts(artifacts: GeneratedArtifacts): void;
21
+ /**
22
+ * Re-checks one consumer shard against the navigation index: a shelf carries
23
+ * exactly the curated products in order, and a category list carries exactly
24
+ * the category's products in order. The expected catalog ID must come from a
25
+ * separately verified catalog, not from the shard being checked.
26
+ */
27
+ export declare function verifyShardArtifact(shard: ShardArtifact, content: string | undefined, verification: ConsumerIndexVerification, catalogId: string): void;
28
+ /**
29
+ * Re-checks the published consumer index against the catalog it indexes. The
30
+ * index is what Adea renders directly, so a contradiction between the two
31
+ * artifacts must never reach a release. Snapshots published before the index
32
+ * existed carry membership only; those are still membership-checked and
33
+ * reported as `hasConsumerIndex: false`.
34
+ */
35
+ export declare function verifyConsumerIndex(content: string, catalog: Pick<Catalog, 'plugins'>, indexContent?: string): ConsumerIndexVerification;
36
+ export declare function verifyCatalogReferences(catalog: Catalog, policy?: CatalogPolicy): void;