@adea-ai/plugins 4.0.1 → 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.
- package/dist/agent-plugins-catalog.d.ts +2 -4
- package/dist/agent-plugins-catalog.js +42 -50
- package/dist/agent-plugins-catalog.js.map +1 -1
- package/dist/agent-plugins-schema.d.ts +8 -0
- package/dist/agent-plugins-schema.js +10 -1
- package/dist/agent-plugins-schema.js.map +1 -1
- package/dist/artifacts.d.ts +57 -0
- package/dist/artifacts.js +159 -0
- package/dist/artifacts.js.map +1 -0
- package/dist/build.d.ts +20 -0
- package/dist/build.js +103 -0
- package/dist/build.js.map +1 -0
- package/dist/capabilities.d.ts +7 -0
- package/dist/capabilities.js +116 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/catalog-store.d.ts +0 -5
- package/dist/catalog-store.js +1 -25
- package/dist/catalog-store.js.map +1 -1
- package/dist/concurrency.d.ts +1 -0
- package/dist/concurrency.js +15 -0
- package/dist/concurrency.js.map +1 -0
- package/dist/consumer-index.d.ts +6 -28
- package/dist/consumer-index.js +7 -8
- package/dist/consumer-index.js.map +1 -1
- package/dist/digest.d.ts +13 -0
- package/dist/digest.js +47 -0
- package/dist/digest.js.map +1 -0
- package/dist/fs-atomic.d.ts +7 -0
- package/dist/fs-atomic.js +30 -0
- package/dist/fs-atomic.js.map +1 -0
- package/dist/harness.js +2 -1
- package/dist/harness.js.map +1 -1
- package/dist/icon-mirror.d.ts +3 -2
- package/dist/icon-mirror.js +51 -63
- package/dist/icon-mirror.js.map +1 -1
- package/dist/icons.d.ts +2 -2
- package/dist/icons.js +4 -12
- package/dist/icons.js.map +1 -1
- package/dist/index.d.ts +16 -315
- package/dist/index.js +12 -1905
- package/dist/index.js.map +1 -1
- package/dist/integrity-manifest.d.ts +43 -13
- package/dist/integrity-manifest.js +28 -17
- package/dist/integrity-manifest.js.map +1 -1
- package/dist/json-values.d.ts +3 -0
- package/dist/json-values.js +10 -0
- package/dist/json-values.js.map +1 -0
- package/dist/plugin-release.d.ts +38 -0
- package/dist/plugin-release.js +321 -0
- package/dist/plugin-release.js.map +1 -0
- package/dist/plugin-skips.d.ts +19 -0
- package/dist/plugin-skips.js +65 -0
- package/dist/plugin-skips.js.map +1 -0
- package/dist/policy.d.ts +13 -0
- package/dist/policy.js +26 -0
- package/dist/policy.js.map +1 -0
- package/dist/portable-catalog.d.ts +4 -4
- package/dist/portable-catalog.js +14 -126
- package/dist/portable-catalog.js.map +1 -1
- package/dist/portable-verify.d.ts +2 -0
- package/dist/portable-verify.js +68 -0
- package/dist/portable-verify.js.map +1 -0
- package/dist/publication.d.ts +6 -3
- package/dist/publication.js +25 -12
- package/dist/publication.js.map +1 -1
- package/dist/published-output.d.ts +17 -0
- package/dist/published-output.js +49 -0
- package/dist/published-output.js.map +1 -0
- package/dist/site-icons.d.ts +2 -3
- package/dist/site-icons.js +4 -3
- package/dist/site-icons.js.map +1 -1
- package/dist/snapshots.d.ts +39 -0
- package/dist/snapshots.js +238 -0
- package/dist/snapshots.js.map +1 -0
- package/dist/source-resolution.d.ts +28 -0
- package/dist/source-resolution.js +158 -0
- package/dist/source-resolution.js.map +1 -0
- package/dist/sources.d.ts +5 -1
- package/dist/sources.js +21 -27
- package/dist/sources.js.map +1 -1
- package/dist/synchronize.d.ts +44 -0
- package/dist/synchronize.js +118 -0
- package/dist/synchronize.js.map +1 -0
- package/dist/taxonomy.d.ts +23 -0
- package/dist/taxonomy.js +62 -0
- package/dist/taxonomy.js.map +1 -0
- package/dist/upstream.d.ts +42 -0
- package/dist/upstream.js +179 -0
- package/dist/upstream.js.map +1 -0
- package/dist/verify-artifacts.d.ts +36 -0
- package/dist/verify-artifacts.js +286 -0
- package/dist/verify-artifacts.js.map +1 -0
- package/native/build-provenance.txt +5 -5
- package/native/staged-reader-win32-arm64.node +0 -0
- package/native/staged-reader-win32-x64.node +0 -0
- package/package.json +2 -4
- package/src/agent-plugins-catalog.test.ts +2 -2
- package/src/agent-plugins-catalog.ts +46 -49
- package/src/agent-plugins-schema.ts +11 -1
- package/src/artifacts.ts +234 -0
- package/src/build.ts +131 -0
- package/src/capabilities.ts +153 -0
- package/src/catalog-store.ts +1 -28
- package/src/concurrency.ts +19 -0
- package/src/consumer-index.test.ts +27 -21
- package/src/consumer-index.ts +12 -35
- package/src/digest.ts +55 -0
- package/src/fs-atomic.ts +32 -0
- package/src/harness.test.ts +4 -32
- package/src/harness.ts +2 -1
- package/src/icon-mirror.ts +57 -64
- package/src/icons.test.ts +0 -4
- package/src/icons.ts +4 -4
- package/src/index.test.ts +52 -48
- package/src/index.ts +50 -2583
- package/src/integrity-manifest.ts +41 -21
- package/src/json-values.ts +11 -0
- package/src/plugin-release.ts +457 -0
- package/src/plugin-skips.ts +110 -0
- package/src/policy.ts +39 -0
- package/src/portable-catalog.test.ts +0 -5
- package/src/portable-catalog.ts +16 -143
- package/src/portable-verify.ts +71 -0
- package/src/publication.test.ts +29 -1
- package/src/publication.ts +32 -13
- package/src/published-output.ts +60 -0
- package/src/site-icons.test.ts +0 -1
- package/src/site-icons.ts +4 -4
- package/src/snapshots.ts +287 -0
- package/src/source-digest.test.ts +3 -7
- package/src/source-resolution.ts +233 -0
- package/src/sources-json.test.ts +0 -1
- package/src/sources.ts +27 -33
- package/src/synchronize.ts +213 -0
- package/src/taxonomy.ts +87 -0
- package/src/upstream.ts +194 -0
- package/src/verify-artifacts.ts +365 -0
- package/src/write-artifacts.test.ts +0 -1
- package/dist/source-digest.d.ts +0 -2
- package/dist/source-digest.js +0 -12
- package/dist/source-digest.js.map +0 -1
- 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;
|
package/dist/taxonomy.js
ADDED
|
@@ -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":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAWvC,MAAM,UAAU,cAAc,CAAC,QAAgB,EAAE,YAAoB;IACnE,OAAO,UAAU,IAAI,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,YAAY,CAAC,EAAE,CAAA;AACzD,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,aAAqB,EACrB,YAAoB,EACpB,SAAiB,EACjB,aAAqB;IAErB,OAAO,SAAS,CAAC,SAAS,EAAE,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,CAAA;AACxF,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAa,EAAE,GAAgB;IAC/D,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,iBAAiB,EAAE,CAAA;IAC5C,OAAO,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAA;AACxD,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,IAAY,EAAE,OAAuB;IACtE,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,iBAAiB,EAAE,CAAA;IAC3C,OAAO,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAA;AAC1C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAOjC,OAAU,EAAE,OAA2C;IACvD,IAAI,CAAC,OAAO;QAAE,OAAO,OAAO,CAAA;IAC5B,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAkB,CAAA;IAC1C,KAAK,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACxD,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;YAC5B,MAAM,GAAG,GAAG,GAAG,QAAQ,KAAK,IAAI,EAAE,CAAA;YAClC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC;gBAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;QAClD,CAAC,CAAC,CAAA;IACJ,CAAC;IACD,MAAM,IAAI,GAAG,CAAC,MAA4B,EAAU,EAAE;QACpD,IAAI,IAAI,GAAG,MAAM,CAAC,iBAAiB,CAAA;QACnC,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;YACzC,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,QAAQ,KAAK,MAAM,CAAC,kBAAkB,EAAE,CAAC,CAAA;YACvE,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,GAAG,IAAI;gBAAE,IAAI,GAAG,KAAK,CAAA;QACvD,CAAC;QACD,OAAO,IAAI,CAAA;IACb,CAAC,CAAA;IACD,OAAO;QACL,GAAG,OAAO;QACV,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;KAC7E,CAAA;AACH,CAAC;AAED,SAAS,aAAa,CAAC,KAAa;IAClC,IAAI,KAAK,GAAG,CAAC,CAAA;IACb,IAAI,GAAG,GAAG,KAAK,CAAC,MAAM,CAAA;IACtB,OAAO,KAAK,GAAG,GAAG,IAAI,KAAK,CAAC,KAAK,CAAC,KAAK,GAAG;QAAE,KAAK,IAAI,CAAC,CAAA;IACtD,OAAO,GAAG,GAAG,KAAK,IAAI,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,KAAK,GAAG;QAAE,GAAG,IAAI,CAAC,CAAA;IACtD,OAAO,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;AAChC,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,KAAa;IAChC,MAAM,MAAM,GACV,aAAa,CACX,KAAK;SACF,IAAI,EAAE;SACN,iBAAiB,EAAE;SACnB,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAC/B,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,SAAS,CAAA;IAC9B,OAAO,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,SAAS,CAAC,CAAC,CAAC,MAAM,CAAA;AACxD,CAAC"}
|
|
@@ -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>;
|
package/dist/upstream.js
ADDED
|
@@ -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;
|