@volter/twin-catalog 0.2.3 → 0.2.4

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/catalog.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "sourceCommit": "d275fdf823a900c7acd092f05570ecf6888b8878",
3
+ "sourceCommit": "d295a1e52d80b36146cac13cfccc403139d8d947",
4
4
  "digest": "1c9e35135ce16a67c8c5ba817277ac2e11869b8a1234206aee5674eb8851a134",
5
5
  "versions": [
6
6
  {
package/docs/process.md CHANGED
@@ -42,6 +42,19 @@ recommendation is moderated separately from a submission and selects a package,
42
42
  version is offered. Prereleases require an explicit version. A World pins package and version; a catalog update
43
43
  does not change that pin. Removing a recommendation is not uninstalling a running World.
44
44
 
45
+ ## Release information for users
46
+
47
+ Each assessed release exposes its artifact's description, license, Node requirements, kernel peer requirements,
48
+ source directory and issue tracker beside its integrity, provenance and measured behavior. README and license links
49
+ point to the source commit verified by npm provenance. They describe that version, not the publisher's current branch.
50
+ Historical assessments without these retained fields show them as unavailable; current registry metadata does not
51
+ fill missing historical evidence. A provenance link establishes source and build identity, not vendor fidelity.
52
+
53
+ Publishers describe useful workflows, setup and throwaway credential requirements, companion services, supported
54
+ SDK/API versions and explicit limitations in the package README. Model replies, simulated email/search and partial
55
+ interfaces are labeled. Declared gaps remain in the coverage denominator. No publisher badge or aggregate grade
56
+ substitutes for the exact release's supported operations, replay results and scope of browser measurements.
57
+
45
58
  ## Submission
46
59
 
47
60
  A release PR adds exactly one `submissions/<id>.json`, with no executable files or index edits:
package/lib/browse.d.mts CHANGED
@@ -45,6 +45,19 @@ export type Release = {
45
45
  assessedAt?: string;
46
46
  };
47
47
  export type CatalogRelease = Release & {
48
+ packageMetadata: null | {
49
+ description: string | null;
50
+ license: string;
51
+ engines: Record<string, string>;
52
+ peerDependencies: Record<string, string>;
53
+ repositoryDirectory: string | null;
54
+ bugs: string | null;
55
+ sourceCommit: string | null;
56
+ readmeUrl: string | null;
57
+ licenseUrl: string | null;
58
+ packageUrl: string;
59
+ issuesUrl: string | null;
60
+ };
48
61
  revoked: { reason: string } | null;
49
62
  selectable: boolean;
50
63
  default: boolean;
package/lib/browse.mjs CHANGED
@@ -6,6 +6,25 @@ import { digest, loadIndex, read, requireThat, selection, stable, submissionId,
6
6
  const textOrder = (a, b) => a < b ? -1 : a > b ? 1 : 0;
7
7
  const releaseKey = (v) => `${v.package}@${v.version}`;
8
8
 
9
+ function packageDetails(bound, source, packageName, version) {
10
+ const metadata = bound?.report.prepared?.packageMetadata;
11
+ if (!metadata) return null;
12
+ const commit = bound.report.prepared?.provenance?.sourceCommit;
13
+ const directory = metadata.repositoryDirectory ?? '';
14
+ const parts = typeof directory === 'string' ? directory.split('/').filter(Boolean) : null;
15
+ const validDirectory = parts && parts.every((part) => part !== '.' && part !== '..' && !part.includes('\\'));
16
+ const sourceRoot = /^[a-f0-9]{40}$/.test(commit ?? '') && validDirectory
17
+ ? `https://github.com/${source.repository}/blob/${commit}/${parts.length ? parts.map(encodeURIComponent).join('/') + '/' : ''}`
18
+ : null;
19
+ let issuesUrl = null;
20
+ try { const url = new URL(metadata.bugs); if (url.protocol === 'https:') issuesUrl = url.href; } catch { /* No usable issue URL was supplied. */ }
21
+ return { ...metadata, sourceCommit: commit ?? null,
22
+ readmeUrl: sourceRoot ? `${sourceRoot}README.md` : null,
23
+ licenseUrl: sourceRoot ? `${sourceRoot}LICENSE` : null,
24
+ packageUrl: `https://www.npmjs.com/package/${packageName}/v/${encodeURIComponent(version)}`,
25
+ issuesUrl };
26
+ }
27
+
9
28
  function repositoryOf(pkg) {
10
29
  const value = typeof pkg.repository === 'string' ? pkg.repository : pkg.repository?.url;
11
30
  const match = /^git\+https:\/\/github\.com\/([A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+?)(?:\.git)?$/.exec(value ?? '') ??
@@ -99,7 +118,8 @@ export function browse(root, { vendor, package: packageName, integrity = null }
99
118
  const revoked = index.revocations.find((r) => r.package === p.name && r.version === v.version);
100
119
  const selectable = v.status === 'live' && !v.version.includes('-') && !revoked;
101
120
  const quick = bound?.report.quick, browser = bound?.report.browser;
102
- return { ...v, revoked: revoked ? { reason: revoked.reason } : null, selectable: Boolean(selectable),
121
+ return { ...v, packageMetadata: packageDetails(bound, source, p.name, v.version),
122
+ revoked: revoked ? { reason: revoked.reason } : null, selectable: Boolean(selectable),
103
123
  default: choice?.p.name === p.name && choice.v.version === v.version,
104
124
  assessment: { recorded: record.assessed, available: Boolean(bound), evidence: record.evidence,
105
125
  input: bound ? { repository: bound.envelope.input.repository, pullRequest: bound.envelope.input.pullRequest,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volter/twin-catalog",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "The moderated twin distribution: approved versions and submission tooling for independent publishers.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -38,7 +38,7 @@
38
38
  "evidence"
39
39
  ],
40
40
  "catalog": {
41
- "sourceCommit": "d275fdf823a900c7acd092f05570ecf6888b8878",
41
+ "sourceCommit": "d295a1e52d80b36146cac13cfccc403139d8d947",
42
42
  "digest": "1c9e35135ce16a67c8c5ba817277ac2e11869b8a1234206aee5674eb8851a134"
43
43
  }
44
44
  }
package/policy.json CHANGED
@@ -2,9 +2,9 @@
2
2
  "schemaVersion": 1,
3
3
  "registry": "https://registry.npmjs.org",
4
4
  "tools": {
5
- "@volter/world-core": "3.0.59",
6
- "@volter/world-runtime": "3.0.59",
7
- "@volter/twin-standard": "1.0.51",
5
+ "@volter/world-core": "3.0.68",
6
+ "@volter/world-runtime": "3.0.68",
7
+ "@volter/twin-standard": "1.0.60",
8
8
  "playwright": "1.63.0"
9
9
  },
10
10
  "bun": "1.3.11",
@@ -77,5 +77,14 @@ const provenance = await verifiedProvenance(await response.json(), source, bytes
77
77
  // Keep a vendor-named package directory for the standard's public directory API; preserve the installed artifact.
78
78
  mkdirSync('/work/packs', { recursive: true });
79
79
  cpSync(join('/work/node_modules', s.package), join('/work/packs', s.vendor), { recursive: true });
80
- write('/work/prepared.json', { schemaVersion: 1, submission: s, integrity: s.integrity, provenance, dependencyLockSha256: digest(readFileSync('/work/package-lock.json', 'utf8')), clientSdkLocks, tools: policy.tools });
80
+ // Retain listing facts from these exact bytes, never the registry's moving latest metadata.
81
+ const packageMetadata = {
82
+ description: typeof pack.description === 'string' ? pack.description : null,
83
+ license: pack.license,
84
+ engines: pack.engines ?? {},
85
+ peerDependencies: pack.peerDependencies ?? {},
86
+ repositoryDirectory: typeof pack.repository === 'object' ? pack.repository.directory ?? null : null,
87
+ bugs: typeof pack.bugs === 'string' ? pack.bugs : pack.bugs?.url ?? null,
88
+ };
89
+ write('/work/prepared.json', { schemaVersion: 1, submission: s, integrity: s.integrity, provenance, packageMetadata, dependencyLockSha256: digest(readFileSync('/work/package-lock.json', 'utf8')), clientSdkLocks, tools: policy.tools });
81
90
  write('/work/world.json', { id: 'catalog-assessment', network: { egress: [] }, services: [] });