publication-payload.ts 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
  1. /** Publication payload policy shared by static manifests and packed tarballs. */
  2. /**
  3. * Whether a package manifest exports generated Host-for-Client metadata.
  4. * @param manifest - parsed package manifest to inspect.
  5. * @returns whether the canonical `./remote` export pair is present.
  6. */
  7. export function hasTypertRemoteNavigation(manifest: unknown): boolean {
  8. if (manifest === null || typeof manifest !== 'object' || Array.isArray(manifest)) return false
  9. const exportsField = (manifest as Record<string, unknown>).exports
  10. if (exportsField === null || typeof exportsField !== 'object' || Array.isArray(exportsField)) return false
  11. const remote = (exportsField as Record<string, unknown>)['./remote']
  12. if (remote === null || typeof remote !== 'object' || Array.isArray(remote)) return false
  13. const entry = remote as Record<string, unknown>
  14. return entry.types === './lib/typert.remote-client.d.ts'
  15. && entry.default === './lib/typert.remote-client.js'
  16. }
  17. /** Normalize a package manifest path or npm tarball member to its payload-relative path. */
  18. function payloadPath(file: string): string {
  19. const normalized = file.replaceAll('\\', '/').replace(/^\.\/+/, '').replace(/\/+$/, '')
  20. return normalized.startsWith('package/') ? normalized.slice('package/'.length) : normalized
  21. }
  22. /**
  23. * Whether a package payload path exposes source or map intermediates. Maps
  24. * serve editor navigation during development, where a workspace consumer
  25. * resolves their source through the package link; a published map resolves
  26. * nothing, so no payload publishes one.
  27. * @param file - manifest path or tarball member to classify.
  28. * @returns whether publishing this path is forbidden.
  29. */
  30. export function isForbiddenPublicationFile(file: string): boolean {
  31. const normalized = payloadPath(file)
  32. return normalized === 'src'
  33. || normalized.startsWith('src/')
  34. || normalized.endsWith('.d.ts.map')
  35. || normalized.endsWith('.js.map')
  36. }
  37. /**
  38. * Reject source and map members in a packed npm tarball.
  39. * @param files - tarball members to validate.
  40. * @param context - tarball identity named in the failure.
  41. */
  42. export function validateTarballPayload(files: readonly string[], context: string): void {
  43. for (const file of files) {
  44. if (!isForbiddenPublicationFile(file)) continue
  45. const normalized = payloadPath(file)
  46. if (normalized === 'src' || normalized.startsWith('src/')) {
  47. throw new Error(`${context} publishes source file ${file}`)
  48. }
  49. throw new Error(`${context} publishes source map ${file}`)
  50. }
  51. }