@bigbinary/neeto-unlisted-links-frontend

中文文档
0.1.5发布于 2026/08/06UNLICENSEDTypeScriptESM + CJS近 30 天下载 2777

Frontend modal and hooks for managing unlisted links across neeto products.

原始使用文档
文档目录5 节
  1. Contents
  2. Development with Host Application
  3. Engine
  4. Frontend package
  5. Instructions for Publishing

neeto-unlisted-links-engine

The neeto-unlisted-links-engine manages unlisted public links across neeto products. An unlisted link is a secret, non-indexed URL that grants read-only access to a specific resource (e.g. an article, project, board) without making the resource globally public. Links can optionally auto-expire.

Contents

  1. Development with Host Application
  2. Instructions for Publishing

Development with Host Application

Engine

Installation

  1. Add the gem to the host application's Gemfile:
    gem "neeto-unlisted-links-engine"
    
  2. Install it:
    bundle install
    
  3. Copy the migration files into your host application:
    bin/rails generate neeto_unlisted_links_engine:install
    
  4. Run the migration:
    bin/rails db:migrate
    

Usage

Include the Unlistable concern on any model whose records can have an unlisted link. The model should belong_to an organization (or any object that responds to root_url):

class Article < ApplicationRecord
  include NeetoUnlistedLinksEngine::Unlistable
  belongs_to :organization
end

The concern wires a has_one :unlisted_link association. You can read/generate links through the NeetoUnlistedLinksEngine::LinksService:

service = NeetoUnlistedLinksEngine::LinksService.new(article)
service.generate_link
service.regenerate_link(expiration_type: "thirty_days",
  expiration_date: 30.days.from_now)
service.update(status: "inactive")
Management routes

The host application is responsible for exposing an authenticated, nested show/regenerate route for the unlistable resource — this is what the frontend package's resourceUrl points at, and what LinksService sits behind. For example, for Documents nested under a project:

resources :projects, param: :sid do
  # ...
  resources :documents, module: :projects, param: :sid do
    resource :unlisted_link, only: %i[show], module: :documents, param: :sid do
      member do
        post :regenerate
      end
    end
    # ...
  end
end

This is distinct from the public-facing route covered below: the routes above are the authenticated, in-app API used to view/regenerate a link (and drive the UnlistedLinks modal), while the public route is the unauthenticated route someone with the secret URL actually visits.

Public access

The engine ships an abstract NeetoUnlistedLinksEngine::UnlistedLinksController that host applications subclass rather than writing the public-facing controller from scratch. It handles rendering the unlisted resource (and its attachments) using a bundled view and layout, and only requires the host controller to implement a single method: #load_record.

# frozen_string_literal: true
class UnlistedLinksController < NeetoUnlistedLinksEngine::UnlistedLinksController
  private
    def load_record
      return nil if @organization.nil?

      unlisted_link = NeetoUnlistedLinksEngine::Link.resolve(params[:unlisted_link_identifier])
      document = unlisted_link&.unlistable
      return nil unless document.is_a?(Document)
      return nil unless document.organization_id == @organization.id

      @record = document
      @content = NeetoEditorEngine.sanitize(@record.body).html_safe
      @attachments = @record.attachments
    end
end
# config/routes.rb
get "/public/:unlisted_link_identifier", to: "unlisted_links#show"

A few things worth calling out in this example:

  • #load_record scopes the lookup to the current @organization (set by whatever before_action the host app already uses to resolve the tenant) and returns early with @record left unset if there's no organization, if the link doesn't resolve, if the resolved resource isn't the expected model (Document here), or if it doesn't belong to that organization. Any of these cases fall through to #render_not_found.
  • @content is passed through NeetoEditorEngine.sanitize and marked html_safe before being handed to the view, since @record.body holds rich, user-authored HTML that shouldn't be rendered unsanitized.
  • The route param is named to match whatever the host app calls it (:unlisted_link_identifier above); just make sure #load_record reads the same param name.

How it works

  • #show calls #load_record, then renders neeto_unlisted_links_engine/unlisted_project/show if @record is present, or calls #render_not_found otherwise.
  • #load_record must be defined by the host controller and is expected to set @record, @content, and @attachments. The base implementation raises NotImplementedError if it isn't overridden.
  • #render_not_found redirects to Rails.application.vault.not_found_redirect_link by default. Override it in the host controller if you need different not-found behavior.
  • The view renders @record.title, the raw @content, and, if @attachments is present, a list of attachment links built from cdn_attachment_url(attachment.blob).
  • The view is rendered inside the engine's neeto_unlisted_links_engine/unlistable layout, a minimal standalone HTML shell (its own <head>, styling, and the neeto editor content stylesheet) so the public page doesn't inherit the host application's normal layout.
# app/controllers/neeto_unlisted_links_engine/unlisted_links_controller.rb (engine)
module NeetoUnlistedLinksEngine
  class UnlistedLinksController < ApplicationController
    before_action :load_record
    layout "neeto_unlisted_links_engine/unlistable"

    def show
      if @record.nil?
        render_not_found
      else
        render "neeto_unlisted_links_engine/unlisted_project/show"
      end
    end

    private
      def load_record
        raise NotImplementedError,
          "Host controller must define #load_record (the one which will " \
          "include the @record and the @content and @attachments )"
      end

      def render_not_found
        redirect_to Rails.application.vault.not_found_redirect_link
      end
  end
end

Frontend package

The matching npm package is @bigbinary/neeto-unlisted-links-frontend. It exports a modal that, given a resource URL prefix, displays the unlisted link, its expiry state, and a regenerate flow.

import { UnlistedLinks } from "@bigbinary/neeto-unlisted-links-frontend";
<UnlistedLinks
  isOpen={isOpen}
  onClose={onClose}
  resourceUrl="/v1/projects/:project_sid/documents/:document_sid/unlisted_link"
/>;

resourceUrl should point at the management route (GET for show, POST .../regenerate for regenerate) for the specific record the modal is open for.

Instructions for Publishing

  1. Bump lib/neeto_unlisted_links_engine/version.rb.
  2. Update CHANGELOG.md.
  3. gem build neeto-unlisted-links-engine.gemspec.
  4. gem push neeto-unlisted-links-engine-<version>.gem --host https://private-gems.neeto.com.
  5. For the frontend package, bump package.json, run yarn build, and npm publish.

版本与发布记录

@bigbinary/neeto-unlisted-links-frontend 共发布 5 个版本,首次发布于 2026/04/27;过去 12 个月发布了 5 个版本。

版本发布日期距今
0.1.5latest2026/08/063 个月前
0.1.42026/07/153 个月前
0.1.32026/06/294 个月前
0.1.22026/05/056 个月前
0.1.12026/04/276 个月前

关于 @bigbinary/neeto-unlisted-links-frontend 的常见问题

@bigbinary/neeto-unlisted-links-frontend 是什么?

Frontend modal and hooks for managing unlisted links across neeto products.

如何安装 @bigbinary/neeto-unlisted-links-frontend?

在项目目录运行 npm install @bigbinary/neeto-unlisted-links-frontend,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:@babel/runtime(7.29.7)、@bigbinary/neeto-atoms(1.0.110)、@bigbinary/neeto-cist(1.0.17)、@bigbinary/neeto-commons-frontend(4.13.152)、@bigbinary/neeto-filters-frontend(4.3.42)、@bigbinary/neeto-molecules(5.3.0)、@bigbinary/neetoui(8.8.3)、@honeybadger-io/js(6.10.1)、@honeybadger-io/react(6.1.25)、@tanstack/react-query(5.59.20)、@tanstack/react-query-devtools(5.59.20)、antd(5.22.1)、axios(1.18.1)、buffer(^6.0.3)、classnames(2.5.1)、crypto-browserify(3.12.1)、dompurify(3.4.12)、formik(2.4.6)、https-browserify(1.0.0)、i18next(22.5.1)、js-logger(1.6.1)、mixpanel-browser(2.45.0)、os-browserify(0.3.0)、path-browserify(^1.0.1)、qs(6.15.2)、ramda(0.29.0)、react(18.3.1)、react-dom(18.3.1)、react-helmet(^6.1.0)、react-i18next(12.3.1)、react-router-dom(5.3.3)、react-toastify(8.0.2)、source-map-loader(4.0.1)、stream-browserify(^3.0.0)、stream-http(3.2.0)、tailwindcss(4.1.17)、tty-browserify(0.0.1)、url(0.11.4)、util(^0.12.5)、vm-browserify(1.1.2)、yup(0.32.11)、zustand(4.4.2)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@bigbinary/neeto-unlisted-links-frontend 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@bigbinary/neeto-unlisted-links-frontend 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@bigbinary/neeto-unlisted-links-frontend 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22.13。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@bigbinary/neeto-unlisted-links-frontend 可以商用吗?

@bigbinary/neeto-unlisted-links-frontend 使用 UNLICENSED 许可。作者声明为 UNLICENSED,即不授予公开使用许可(与公共领域的 Unlicense 不同)。使用前需获得作者授权。以上为概括,不构成法律意见,请以许可原文为准。

@bigbinary/neeto-unlisted-links-frontend 的下载量有多少?

根据 npm 官方下载统计,@bigbinary/neeto-unlisted-links-frontend 在 2026/10/08 – 2026/11/06 这 30 天内被下载 2,777 次,日均约 93 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@bigbinary/neeto-unlisted-links-frontend 还在维护吗?

最新版本 0.1.5 发布于 2026/08/06(3 个月前);至今共发布 5 个版本,其中过去 12 个月发布了 5 个;首次发布于 2026/04/27。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。