@volter/twin-standard 1.0.34 → 1.0.36

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.
@@ -13,9 +13,10 @@ import { existsSync } from 'node:fs';
13
13
  import { request as httpsRequest } from 'node:https';
14
14
  import { createRequire } from 'node:module';
15
15
  import { pathToFileURL } from 'node:url';
16
+ import { standardPackageFile } from "../package-file.js";
16
17
  // The pins live in ../../client-sdks with their own lockfile, installed here on first use: some carry advisories with no
17
18
  // fix in the line an application pins, so the repository's install (and a release, .github/release-scan.mjs) never does.
18
- const SDKS = new URL('../../client-sdks/', import.meta.url);
19
+ const SDKS = standardPackageFile('client-sdks/');
19
20
  async function sdkOf(name) {
20
21
  if (!existsSync(new URL('node_modules/', SDKS))) {
21
22
  const install = spawnSync('bun', ['install', '--frozen-lockfile', '--ignore-scripts'], { cwd: SDKS, stdio: 'inherit' });
@@ -33,6 +33,7 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
33
33
  import { parseExactJson, exactInteger } from '@volter/world-core/exact-json';
34
34
  import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
35
35
  import { basename, dirname, join, relative, resolve } from 'node:path';
36
+ import { standardPackageFile } from "./package-file.js";
36
37
  import { gunzipSync } from 'node:zlib';
37
38
  import { parse as parseYaml } from 'yaml';
38
39
  import { coreFor } from '@volter/world-core';
@@ -476,7 +477,7 @@ export async function createPack(args) {
476
477
  // the package's licence, the platform's (Apache-2.0), as every published pack carries it
477
478
  const licence = join(dir, 'LICENSE');
478
479
  if (!existsSync(licence)) {
479
- writeFileSync(licence, readFileSync(new URL('../LICENSE', import.meta.url)));
480
+ writeFileSync(licence, readFileSync(standardPackageFile('LICENSE')));
480
481
  console.log('create-pack: wrote LICENSE');
481
482
  }
482
483
  // the handler map each fetch imports, empty until the families are written (--index again then)
@@ -526,7 +527,10 @@ export async function createPack(args) {
526
527
  console.log(`create-pack: wrote ${join(dir, 'src', 'fetch.ts')}`);
527
528
  // a pack's own index (a lane's is the vendor's to name): the descriptor with what the kernel derives from the surface
528
529
  if (existsSync(join(dir, 'package.json'))) {
529
- const vendor = parseExactJson(readFileSync(join(dir, 'package.json'), 'utf8')).name.replace(/^@volter\/twin-/, '');
530
+ const { manifest } = await import(__rewriteRelativeImportExtension(join(dir, 'src', 'manifest.ts')));
531
+ const vendor = manifest?.vendor;
532
+ if (!vendor || !/^[a-z][a-z0-9-]*$/.test(vendor))
533
+ throw new Error('Pack manifest must declare its vendor identity independently of the npm package name');
530
534
  writeFileSync(join(dir, 'src', 'index.ts'), packIndexFile(dir, vendor));
531
535
  console.log(`create-pack: wrote ${join(dir, 'src', 'index.ts')}`);
532
536
  // what the grade's typecheck compiles: a pack made before init wrote it gets it here
@@ -0,0 +1,2 @@
1
+ /** Package-owned data beside src/, or beside dist/ when the released entrypoints are compiled. */
2
+ export declare function standardPackageFile(name: 'package.json' | 'LICENSE' | 'client-sdks/'): URL;
@@ -0,0 +1,11 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ /** Package-owned data beside src/, or beside dist/ when the released entrypoints are compiled. */
3
+ export function standardPackageFile(name) {
4
+ for (const parent of ['../', '../../']) {
5
+ const root = new URL(parent, import.meta.url);
6
+ const manifest = new URL('package.json', root);
7
+ if (existsSync(manifest) && JSON.parse(readFileSync(manifest, 'utf8')).name === '@volter/twin-standard')
8
+ return new URL(name, root);
9
+ }
10
+ throw new Error('Cannot locate the twin-standard package manifest');
11
+ }
@@ -6,7 +6,7 @@ export type PublishedGate = {
6
6
  failures: string[];
7
7
  }>;
8
8
  };
9
- /** The vendor a package twins: its name without its scope and the `twin-` prefix (`@volter/twin-supabase` is supabase). */
9
+ /** Conventional-name fallback for artifacts predating generated identity facts; not an independent package identity. */
10
10
  export declare const vendorOfPackage: (name: string) => string;
11
11
  /** The conformance of `spec` as the registry serves it: the published tarball with its own dependencies installed,
12
12
  * served and read against the kernel (kernelDir). */
@@ -8,7 +8,7 @@ import { tmpdir } from 'node:os';
8
8
  import { dirname, join } from 'node:path';
9
9
  import { conformance } from "./conformance.js";
10
10
  import { p3Gate } from "./gate.js";
11
- /** The vendor a package twins: its name without its scope and the `twin-` prefix (`@volter/twin-supabase` is supabase). */
11
+ /** Conventional-name fallback for artifacts predating generated identity facts; not an independent package identity. */
12
12
  export const vendorOfPackage = (name) => name.replace(/^@[^/]+\//, '').replace(/^twin-/, '');
13
13
  /** `spec` (`<name>@<version>`) as the registry serves it, unpacked under its vendor's name in a scratch directory, handed
14
14
  * to `use`; throws when it cannot be fetched or unpacked. */
@@ -23,7 +23,15 @@ async function withPublished(spec, opts, use) {
23
23
  if (untar.status !== 0)
24
24
  throw new Error(`${spec}: the tarball does not unpack (${String(untar.stderr).trim()})`);
25
25
  const name = JSON.parse(readFileSync(join(tmp, 'package', 'package.json'), 'utf8')).name;
26
- const dir = join(tmp, vendorOfPackage(name));
26
+ const factsFile = join(tmp, 'package', 'generated', 'pack-facts.json');
27
+ const facts = existsSync(factsFile) ? JSON.parse(readFileSync(factsFile, 'utf8')) : undefined;
28
+ const vendors = Object.keys(facts?.packs ?? {});
29
+ if (facts && vendors.length !== 1)
30
+ throw new Error(`${spec}: generated facts must identify one vendor`);
31
+ const vendor = facts ? vendors[0] : vendorOfPackage(name);
32
+ if (!/^[a-z][a-z0-9-]*$/.test(vendor))
33
+ throw new Error(`${spec}: invalid vendor identity`);
34
+ const dir = join(tmp, vendor);
27
35
  renameSync(join(tmp, 'package'), dir);
28
36
  return await use(dir, tmp);
29
37
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volter/twin-standard",
3
- "version": "1.0.34",
3
+ "version": "1.0.36",
4
4
  "description": "The Protocol 3 standard for Volter twin packs: the criteria a pack is graded by, the grader, the gate a pack repository and the twin catalog run on every change and submission, and the spec derivation the grade checks against. Pin a version: every place a pack is judged judges by that standard.",
5
5
  "keywords": [
6
6
  "twin",
@@ -19,6 +19,8 @@
19
19
  "src",
20
20
  "README.md",
21
21
  "LICENSE",
22
+ "client-sdks/package.json",
23
+ "client-sdks/bun.lock",
22
24
  "!**/*.test.ts",
23
25
  "dist"
24
26
  ],
@@ -27,6 +29,9 @@
27
29
  "url": "git+https://github.com/volter-ai/twin-world.git",
28
30
  "directory": "packages/twin-standard"
29
31
  },
32
+ "assessmentClientSdks": [
33
+ "client-sdks"
34
+ ],
30
35
  "homepage": "https://github.com/volter-ai/twin-world/tree/main/packages/twin-standard#readme",
31
36
  "type": "module",
32
37
  "exports": {
@@ -70,7 +75,7 @@
70
75
  "yaml": "2.9.0"
71
76
  },
72
77
  "peerDependencies": {
73
- "@volter/world-core": "3.0.42",
78
+ "@volter/world-core": "3.0.44",
74
79
  "@volter/world-runtime": "*",
75
80
  "playwright": "^1.63.0"
76
81
  },
package/src/cli.ts CHANGED
@@ -19,6 +19,7 @@ import { relative, resolve } from 'node:path';
19
19
  import { unitsOf, p3Gate } from './gate.ts';
20
20
  import { grade, STANDARDS } from './grade.ts';
21
21
  import { withCheckoutFiles } from './protocol-3.ts';
22
+ import { standardPackageFile } from './package-file.ts';
22
23
  import { gatePublished } from './published.ts';
23
24
 
24
25
  const [command, ...args] = process.argv.slice(2);
@@ -28,7 +29,7 @@ const usage = (): never => {
28
29
  };
29
30
 
30
31
  if (command === '--version') {
31
- const pkg = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')) as { version: string };
32
+ const pkg = JSON.parse(readFileSync(standardPackageFile('package.json'), 'utf8')) as { version: string };
32
33
  console.log(`@volter/twin-standard ${pkg.version} · ${STANDARDS.map((s) => `${s.id}@${s.version}`).join(' ')}`);
33
34
  } else if (command === 'gate') {
34
35
  const [repoArg, ...only] = args;
@@ -6,10 +6,11 @@ import { request as httpsRequest } from 'node:https';
6
6
  import { createRequire } from 'node:module';
7
7
  import { pathToFileURL } from 'node:url';
8
8
  import type { ClientCase, ClientContext } from './harness.ts';
9
+ import { standardPackageFile } from '../package-file.ts';
9
10
 
10
11
  // The pins live in ../../client-sdks with their own lockfile, installed here on first use: some carry advisories with no
11
12
  // fix in the line an application pins, so the repository's install (and a release, .github/release-scan.mjs) never does.
12
- const SDKS = new URL('../../client-sdks/', import.meta.url);
13
+ const SDKS = standardPackageFile('client-sdks/');
13
14
  async function sdkOf(name: string): Promise<any> {
14
15
  if (!existsSync(new URL('node_modules/', SDKS))) {
15
16
  const install = spawnSync('bun', ['install', '--frozen-lockfile', '--ignore-scripts'], { cwd: SDKS, stdio: 'inherit' });
@@ -25,6 +25,7 @@
25
25
  import { parseExactJson, exactInteger } from '@volter/world-core/exact-json';
26
26
  import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
27
27
  import { basename, dirname, join, relative, resolve } from 'node:path';
28
+ import { standardPackageFile } from './package-file.ts';
28
29
  import { gunzipSync } from 'node:zlib';
29
30
  import { parse as parseYaml } from 'yaml';
30
31
  import { coreFor, type DerivedManifest, type DerivedOperation } from '@volter/world-core';
@@ -457,7 +458,7 @@ export async function createPack(args: string[]): Promise<void> {
457
458
  }
458
459
  // the package's licence, the platform's (Apache-2.0), as every published pack carries it
459
460
  const licence = join(dir, 'LICENSE');
460
- if (!existsSync(licence)) { writeFileSync(licence, readFileSync(new URL('../LICENSE', import.meta.url))); console.log('create-pack: wrote LICENSE'); }
461
+ if (!existsSync(licence)) { writeFileSync(licence, readFileSync(standardPackageFile('LICENSE'))); console.log('create-pack: wrote LICENSE'); }
461
462
  // the handler map each fetch imports, empty until the families are written (--index again then)
462
463
  for (const at of lanesArg.length ? [...lanesArg.map((l) => join(dir, l)), dir] : [dir]) {
463
464
  if (at === dir && lanesArg.length) { const f = join(dir, 'src', 'fetch.ts'); if (!existsSync(f)) { writeFileSync(f, packFetchFile(dir, fetchName(dir))); console.log('create-pack: wrote src/fetch.ts'); } continue; }
@@ -488,7 +489,9 @@ export async function createPack(args: string[]): Promise<void> {
488
489
  console.log(`create-pack: wrote ${join(dir, 'src', 'fetch.ts')}`);
489
490
  // a pack's own index (a lane's is the vendor's to name): the descriptor with what the kernel derives from the surface
490
491
  if (existsSync(join(dir, 'package.json'))) {
491
- const vendor = (parseExactJson(readFileSync(join(dir, 'package.json'), 'utf8')) as { name: string }).name.replace(/^@volter\/twin-/, '');
492
+ const { manifest } = await import(join(dir, 'src', 'manifest.ts')) as { manifest?: { vendor?: string } };
493
+ const vendor = manifest?.vendor;
494
+ if (!vendor || !/^[a-z][a-z0-9-]*$/.test(vendor)) throw new Error('Pack manifest must declare its vendor identity independently of the npm package name');
492
495
  writeFileSync(join(dir, 'src', 'index.ts'), packIndexFile(dir, vendor));
493
496
  console.log(`create-pack: wrote ${join(dir, 'src', 'index.ts')}`);
494
497
  // what the grade's typecheck compiles: a pack made before init wrote it gets it here
@@ -0,0 +1,11 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+
3
+ /** Package-owned data beside src/, or beside dist/ when the released entrypoints are compiled. */
4
+ export function standardPackageFile(name: 'package.json' | 'LICENSE' | 'client-sdks/'): URL {
5
+ for (const parent of ['../', '../../']) {
6
+ const root = new URL(parent, import.meta.url);
7
+ const manifest = new URL('package.json', root);
8
+ if (existsSync(manifest) && JSON.parse(readFileSync(manifest, 'utf8')).name === '@volter/twin-standard') return new URL(name, root);
9
+ }
10
+ throw new Error('Cannot locate the twin-standard package manifest');
11
+ }
package/src/published.ts CHANGED
@@ -11,7 +11,7 @@ import { p3Gate } from './gate.ts';
11
11
 
12
12
  export type PublishedGate = { spec: string; failures: Array<{ unit: string; failures: string[] }> };
13
13
 
14
- /** The vendor a package twins: its name without its scope and the `twin-` prefix (`@volter/twin-supabase` is supabase). */
14
+ /** Conventional-name fallback for artifacts predating generated identity facts; not an independent package identity. */
15
15
  export const vendorOfPackage = (name: string): string => name.replace(/^@[^/]+\//, '').replace(/^twin-/, '');
16
16
 
17
17
  /** `spec` (`<name>@<version>`) as the registry serves it, unpacked under its vendor's name in a scratch directory, handed
@@ -25,7 +25,13 @@ async function withPublished<T>(spec: string, opts: { registry?: string }, use:
25
25
  const untar = spawnSync('tar', ['-xzf', join(tmp, tarball), '-C', tmp], { encoding: 'utf8' });
26
26
  if (untar.status !== 0) throw new Error(`${spec}: the tarball does not unpack (${String(untar.stderr).trim()})`);
27
27
  const name = (JSON.parse(readFileSync(join(tmp, 'package', 'package.json'), 'utf8')) as { name: string }).name;
28
- const dir = join(tmp, vendorOfPackage(name));
28
+ const factsFile = join(tmp, 'package', 'generated', 'pack-facts.json');
29
+ const facts = existsSync(factsFile) ? JSON.parse(readFileSync(factsFile, 'utf8')) as { packs?: Record<string, unknown> } : undefined;
30
+ const vendors = Object.keys(facts?.packs ?? {});
31
+ if (facts && vendors.length !== 1) throw new Error(`${spec}: generated facts must identify one vendor`);
32
+ const vendor = facts ? vendors[0]! : vendorOfPackage(name);
33
+ if (!/^[a-z][a-z0-9-]*$/.test(vendor)) throw new Error(`${spec}: invalid vendor identity`);
34
+ const dir = join(tmp, vendor);
29
35
  renameSync(join(tmp, 'package'), dir);
30
36
  return await use(dir, tmp);
31
37
  } finally {