@f5-sales-demo/xcsh 23.1.0 → 23.2.2

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.
@@ -1,4 +1,4 @@
1
1
  [diffend] Oversized file quarantined before diffing.
2
2
  name: package/src/internal-urls/api-spec-index.generated.ts
3
3
  size: 41998054 bytes
4
- sha256: 4e7b01134673fd54498bfeb2e8817f56f0b976240b54b8e63315412d31adf2fe
4
+ sha256: 5f7ecc36f0680afc707380a988aefc9339bf005c08406d615ffa1860de1f3c6d
@@ -17,17 +17,17 @@ export interface BuildInfo {
17
17
  }
18
18
 
19
19
  export const BUILD_INFO: BuildInfo = {
20
- "version": "23.1.0",
21
- "commit": "d02b4c9f23bb3308d5e067c5842dc53e54d73a57",
22
- "shortCommit": "d02b4c9",
20
+ "version": "23.2.2",
21
+ "commit": "985e73f7cb97d485eabd38967868af3acc5ec7ae",
22
+ "shortCommit": "985e73f",
23
23
  "branch": "main",
24
- "tag": "v23.1.0",
25
- "commitDate": "2026-10-08T23:03:03Z",
26
- "buildDate": "2026-10-08T23:51:13.103Z",
24
+ "tag": "v23.2.2",
25
+ "commitDate": "2026-10-09T18:01:54Z",
26
+ "buildDate": "2026-10-09T18:48:44.757Z",
27
27
  "dirty": true,
28
28
  "prNumber": "",
29
29
  "repoUrl": "https://github.com/f5-sales-demo/xcsh",
30
30
  "repoSlug": "f5-sales-demo/xcsh",
31
- "commitUrl": "https://github.com/f5-sales-demo/xcsh/commit/d02b4c9f23bb3308d5e067c5842dc53e54d73a57",
32
- "releaseUrl": "https://github.com/f5-sales-demo/xcsh/releases/tag/v23.1.0"
31
+ "commitUrl": "https://github.com/f5-sales-demo/xcsh/commit/985e73f7cb97d485eabd38967868af3acc5ec7ae",
32
+ "releaseUrl": "https://github.com/f5-sales-demo/xcsh/releases/tag/v23.2.2"
33
33
  };
@@ -243,7 +243,7 @@ function verifyDatabase(database: Database, assets: EmbeddedDocumentationAssets)
243
243
  asset_count: String(assets.assetCount),
244
244
  document_count: String(assets.documentCount),
245
245
  fingerprint: assets.fingerprint,
246
- index_schema: "3",
246
+ index_schema: "4",
247
247
  release_tag: assets.releaseTag,
248
248
  source_commit: assets.sourceCommit,
249
249
  };
@@ -486,6 +486,16 @@ export function createEmbeddedDocumentationRepository(
486
486
  },
487
487
  readDocument: async (source, stablePath, anchor): Promise<DocumentationDocument | null> => {
488
488
  const current = await state();
489
+ const route = current.database
490
+ .query(
491
+ "SELECT target_source, target_stable_path FROM documentation_routes WHERE source = ? AND stable_path = ?",
492
+ )
493
+ .get(source, stablePath) as { target_source: DocumentationSource; target_stable_path: string } | null;
494
+ if (route) {
495
+ source = route.target_source;
496
+ stablePath = route.target_stable_path;
497
+ }
498
+
489
499
  const row = current.database
490
500
  .query(
491
501
  "SELECT title, original_url, markdown, lifecycle, replacement_url FROM documentation_documents WHERE source = ? AND stable_path = ?",
@@ -516,6 +526,16 @@ export function createEmbeddedDocumentationRepository(
516
526
  },
517
527
  readAsset: async (source, stablePath, filename): Promise<DocumentationAsset | null> => {
518
528
  const current = await state();
529
+ const route = current.database
530
+ .query(
531
+ "SELECT target_source, target_stable_path FROM documentation_routes WHERE source = ? AND stable_path = ?",
532
+ )
533
+ .get(source, stablePath) as { target_source: DocumentationSource; target_stable_path: string } | null;
534
+ if (route) {
535
+ source = route.target_source;
536
+ stablePath = route.target_stable_path;
537
+ }
538
+
519
539
  const row = current.database
520
540
  .query(
521
541
  "SELECT source, stable_path, filename, archive_path, mime_type, sha256, size_bytes FROM documentation_assets WHERE source = ? AND stable_path = ? AND filename = ?",
@@ -41,7 +41,7 @@ const COMMIT = /^[a-f0-9]{40}$/;
41
41
  const RELEASE_TAG = /^content-[0-9]{8}T[0-9]{6}Z$/;
42
42
  const TIMESTAMP = /^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$/;
43
43
  const FIXED_TIME = "2000-01-01T00:00:00.000Z";
44
- const DOCUMENTATION_INDEX_SCHEMA_VERSION = 3;
44
+ const DOCUMENTATION_INDEX_SCHEMA_VERSION = 4;
45
45
  const MANIFEST_KEYS = [
46
46
  "asset_count",
47
47
  "assets",
@@ -142,7 +142,15 @@ export interface VerifiedDocumentationAsset {
142
142
  readonly sizeBytes: number;
143
143
  }
144
144
 
145
+ export interface DocumentationRouteAlias {
146
+ readonly path: string;
147
+ readonly target: string;
148
+ readonly url: string;
149
+ }
150
+
145
151
  export interface VerifiedDocumentationSnapshot {
152
+ readonly aliases?: readonly DocumentationRouteAlias[];
153
+ readonly enrichmentArtifactSha256?: string;
146
154
  readonly archivePath: string;
147
155
  readonly releaseTag: string;
148
156
  readonly sourceCommit: string;
@@ -623,7 +631,11 @@ export async function verifyDocumentationRelease(
623
631
  }
624
632
 
625
633
  const manifest = parseJson(manifestEntry.data, "documentation manifest");
626
- exactKeys(manifest, MANIFEST_KEYS, "documentation manifest");
634
+ exactKeys(
635
+ manifest,
636
+ [...MANIFEST_KEYS, ...(Object.hasOwn(manifest, "enrichment") ? ["enrichment"] : [])],
637
+ "documentation manifest",
638
+ );
627
639
  if (manifest.schema_version !== 2) throw new Error("documentation manifest schema version is invalid");
628
640
  string(manifest.tool_version, "documentation manifest tool version");
629
641
  validateTimestamp(manifest.started_at, "documentation manifest started_at");
@@ -775,8 +787,60 @@ export async function verifyDocumentationRelease(
775
787
  if (JSON.stringify([...seen].sort()) !== JSON.stringify(contentNames))
776
788
  throw new Error("documentation manifest content member set mismatch");
777
789
 
790
+ const aliases: DocumentationRouteAlias[] = [];
791
+ let enrichmentArtifactSha256: string | undefined;
792
+ if (Object.hasOwn(manifest, "enrichment")) {
793
+ const enrichment = object(manifest.enrichment, "enrichment");
794
+ exactKeys(enrichment, ["artifact_sha256", "aliases"], "enrichment");
795
+ enrichmentArtifactSha256 = string(enrichment.artifact_sha256, "enrichment artifact digest");
796
+ if (!SHA256.test(enrichmentArtifactSha256) || !Array.isArray(enrichment.aliases))
797
+ throw new Error("invalid enrichment digest or aliases");
798
+ const canonicalPaths = new Set(documents.map(d => d.archivePath));
799
+ const aliasPaths = new Set<string>();
800
+ for (const value of enrichment.aliases) {
801
+ const alias = object(value, "enrichment alias");
802
+ exactKeys(alias, ["path", "target", "url"], "enrichment alias");
803
+ const route = {
804
+ path: string(alias.path, "enrichment alias path"),
805
+ target: string(alias.target, "enrichment alias target"),
806
+ url: string(alias.url, "enrichment alias URL"),
807
+ };
808
+ try {
809
+ validateMemberName(route.path);
810
+ validateMemberName(route.target);
811
+ } catch (error) {
812
+ throw new Error("unsafe enrichment alias path", { cause: error });
813
+ }
814
+ if (
815
+ !route.path.endsWith("/index.md") ||
816
+ !route.target.endsWith("/index.md") ||
817
+ canonicalPaths.has(route.path) ||
818
+ aliasPaths.has(route.path) ||
819
+ !canonicalPaths.has(route.target)
820
+ )
821
+ throw new Error("conflicting, dangling, or chained enrichment alias");
822
+ const source = route.path.split("/")[1] as DocumentationSource;
823
+ if (
824
+ !/^content\/[a-z0-9-]+\/(?:[A-Za-z0-9_~.-]+\/)*index\.md$/.test(route.path) ||
825
+ !/^content\/[a-z0-9-]+\/(?:[A-Za-z0-9_~.-]+\/)*index\.md$/.test(route.target)
826
+ )
827
+ throw new Error("unsafe enrichment alias route");
828
+ if (
829
+ source === "docs-cloud-f5-com" &&
830
+ route.url !== `${SOURCE_ROOT_URLS[source]}/${stableDocumentPath(route.path, source)}`
831
+ )
832
+ throw new Error("enrichment alias URL does not match its route");
833
+ validateCorpusUrl(route.url, source, "enrichment alias URL");
834
+ aliasPaths.add(route.path);
835
+ aliases.push(route);
836
+ }
837
+ aliases.sort((a, b) => a.path.localeCompare(b.path));
838
+ }
839
+
778
840
  return {
779
841
  archivePath,
842
+ aliases,
843
+ enrichmentArtifactSha256,
780
844
  releaseTag: pin.release_tag,
781
845
  sourceCommit: pin.source_commit,
782
846
  archiveSha256: pin.assets["html-to-markdown-content.tar.gz"].sha256,
@@ -790,6 +854,8 @@ function fingerprint(snapshot: VerifiedDocumentationSnapshot): string {
790
854
  JSON.stringify({
791
855
  archiveSha256: snapshot.archiveSha256,
792
856
  indexSchema: DOCUMENTATION_INDEX_SCHEMA_VERSION,
857
+ aliases: snapshot.aliases ?? [],
858
+ enrichmentArtifactSha256: snapshot.enrichmentArtifactSha256 ?? null,
793
859
  releaseTag: snapshot.releaseTag,
794
860
  sourceCommit: snapshot.sourceCommit,
795
861
  qmdVersion: "2.8.3",
@@ -829,6 +895,24 @@ function canonicalizeDatabase(
829
895
  key TEXT PRIMARY KEY NOT NULL,
830
896
  value TEXT NOT NULL
831
897
  )`);
898
+ db.exec(`CREATE TABLE documentation_routes (
899
+ source TEXT NOT NULL, stable_path TEXT NOT NULL,
900
+ target_source TEXT NOT NULL, target_stable_path TEXT NOT NULL,
901
+ original_url TEXT NOT NULL, PRIMARY KEY (source, stable_path)
902
+ )`);
903
+ const insertRoute = db.query("INSERT INTO documentation_routes VALUES (?, ?, ?, ?, ?)");
904
+ for (const alias of snapshot.aliases ?? []) {
905
+ const source = alias.path.split("/")[1] as DocumentationSource;
906
+ const targetSource = alias.target.split("/")[1] as DocumentationSource;
907
+ insertRoute.run(
908
+ source,
909
+ stableDocumentPath(alias.path, source),
910
+ targetSource,
911
+ stableDocumentPath(alias.target, targetSource),
912
+ alias.url,
913
+ );
914
+ }
915
+
832
916
  db.exec(`CREATE TABLE documentation_documents (
833
917
  source TEXT NOT NULL,
834
918
  stable_path TEXT NOT NULL,