@bigbinary/neeto-google-drive-frontend

中文文档
2.0.16发布于 2026/10/01UNLICENSEDTypeScriptESM + CJS近 30 天下载 2259

Reusable Google Drive integration for Neeto products.

原始使用文档
文档目录33 节
  1. What the nano provides
  2. Backend engine
  3. Frontend package
  4. What the host product must provide
  5. Quick start
  6. 1. Install the backend engine
  7. 2. Configure Google OAuth
  8. 3. Add the owner contract
  9. 4. Scope and authorize the engine controllers
  10. 5. Install and render the frontend
  11. Backend API
  12. Data owned by the engine
  13. Using the Drive client from a host exporter
  14. neetoForm example: implemented
  15. Model adapter
  16. Background export
  17. neetoCal example: planned
  18. Planned initializer
  19. Planned model adapter
  20. Planned controller configuration
  21. Planned frontend adapter
  22. Frontend props
  23. GoogleDriveIntegration
  24. GoogleDriveSettings
  25. useGoogleDrive
  26. Connection and folder behavior
  27. Connect
  28. Reconnect
  29. Disconnect
  30. Error handling
  31. Testing
  32. Local frontend development
  33. Publishing

neeto-google-drive-nano

Start with Quick start. It is the shortest path to a working, per-owner Google Drive connection.

This nano provides a reusable Rails engine and frontend package for connecting a Neeto product resource to Google Drive.

Examples of an owner and its exported resource:

ProductIntegration ownerExported resource
neetoFormFormSubmission
neetoCalMeetingBooking

Each owner gets its own Google account connection. Google Drive credentials are not shared with Google Sheets or with another owner.

What the nano provides

Backend engine

The Rails engine owns:

  1. Google OAuth with the drive.file and userinfo.email scopes.
  2. Encrypted access-token and refresh-token storage.
  3. Per-owner connection status, account details, settings, and main-folder ID.
  4. Google Drive file, folder, upload, query, and token-refresh operations.
  5. Connect, configure, disconnect, and OAuth callback API endpoints.

It also handles these edge cases:

  • It reuses an omitted refresh token only when reconnecting the same Google account.
  • It creates a new main folder when the stored folder was deleted or trashed.
  • It synchronizes a folder name changed directly in Google Drive.
  • It prevents concurrent requests from leaving duplicate main folders.
  • It disconnects invalid authorization without deleting existing Drive files.

Frontend package

The frontend package exports:

import {
  GoogleDriveIcon,
  GoogleDriveIntegration,
  GoogleDriveSettings,
  useGoogleDrive,
} from "@bigbinary/neeto-google-drive-frontend";

The connection UI includes:

  • Sign in with Google.
  • Connected-account email.
  • Copy and open main-folder link.
  • Configure and disconnect actions.
  • OAuth and authorization error messages.

The settings UI includes:

  • Main-folder name.
  • Per-resource folder toggle and naming-field builder.
  • Save, cancel, loading, and missing-integration states.
  • An optional renderAdditionalSettings slot for host-owned options.

Product-specific settings such as attachment-field selection or a PDF export toggle are not built into the nano. The host renders them through renderAdditionalSettings and stores their values in additional_settings.

What the host product must provide

The nano does not know how a form submission or calendar booking works. The host product owns:

  1. Tenant-scoped owner lookup and authorization.
  2. Product-specific naming fields and any extra settings UI.
  3. The background job that decides when to export.
  4. Resource formatting, attachment lookup, and PDF generation.
  5. Product routes, page layout, breadcrumbs, help links, and lifecycle cleanup.

There is no reconnect email in the nano. A host can add one, but it is not required for the integration to work.

Quick start

1. Install the backend engine

Add the gem:

source "NEETO_GEM_SERVER_URL" do
  gem "neeto-google-drive-engine"
end

Install it:

bundle install

Mount the engine in config/routes.rb:

Rails.application.routes.draw do
  mount NeetoGoogleDriveEngine::Engine, at: "/neeto_google_drive"
end

Copy and run the migration:

bundle exec rails neeto_google_drive_engine:install:migrations
bundle exec rails db:migrate

2. Configure Google OAuth

Create config/initializers/neeto_google_drive_engine.rb:

# frozen_string_literal: true

NeetoGoogleDriveEngine.application_name = "NeetoForm"
NeetoGoogleDriveEngine.oauth_app_url =
  Rails.application.vault.google_drive[:oauth_app_url]
NeetoGoogleDriveEngine.oauth_client_id =
  Rails.application.vault.google_drive[:client_id]
NeetoGoogleDriveEngine.oauth_client_secret =
  Rails.application.vault.google_drive[:client_secret]
NeetoGoogleDriveEngine.oauth_state_private_key =
  Rails.application.vault.jwt[:connect_private_key]
NeetoGoogleDriveEngine.oauth_state_public_key =
  Rails.application.vault.jwt[:connect_public_key]
NeetoGoogleDriveEngine.user_class = "User"

Register this complete redirect URI in the Google OAuth client:

<oauth_app_url>/neeto_google_drive/api/v1/oauth

For example:

https://connect.neetoform.net/neeto_google_drive/api/v1/oauth

Use a dedicated Google Drive OAuth configuration. Do not reuse a Google Sheets token or make Drive credentials shared across owners.

The OAuth state is signed with RS256 and expires after two hours. The callback rejects invalid, expired, or tenant-inaccessible owner data.

3. Add the owner contract

Include NeetoGoogleDriveEngine::HasGoogleDrive in the model that owns the connection:

class Form < ApplicationRecord
  include NeetoGoogleDriveEngine::HasGoogleDrive
  include GoogleDriveIntegrable
end

The host adapter can implement these methods:

module GoogleDriveIntegrable
  extend ActiveSupport::Concern

  def google_drive_default_folder_name
    name
  end

  def google_drive_default_resource_folder_name_fields
    []
  end

  def google_drive_default_additional_settings
    {}
  end

  def google_drive_naming_fields
    raise NotImplementedError
  end

  def google_drive_additional_settings_data
    {}
  end

  def google_drive_redirect_url(query)
    raise NotImplementedError
  end
end

Method responsibilities:

MethodRequiredPurpose
google_drive_naming_fieldsYesFields available in the resource-folder name builder
google_drive_redirect_urlYesAbsolute product URL used after OAuth
google_drive_default_folder_nameNoInitial main-folder name; defaults to name
google_drive_default_resource_folder_name_fieldsNoInitially selected naming-field IDs
google_drive_default_additional_settingsNoDefault host-owned settings hash; defaults to {}
google_drive_additional_settings_dataNoMetadata for the host settings UI; defaults to {}

A naming field has this shape:

{ id: "customer_name", label: "Customer name", kind: "text" }

Only id and label are required by the frontend.

Product-specific options (attachments, PDF, notes, and so on) belong in additional_settings. Use google_drive_additional_settings_data to send UI metadata such as available attachment fields to renderAdditionalSettings.

4. Scope and authorize the engine controllers

The engine intentionally leaves product authorization to the host.

Override the API controller:

# app/overrides/controllers/neeto_google_drive_engine/api/v1/base_controller_override.rb

NeetoGoogleDriveEngine::Api::V1::BaseController.class_eval do
  private

    def load_owner
      @owner = current_user.organization.forms.find(params[:owner_id])
    end

    def authorize_google_drive!
      authorize(:form_setting, :can_manage_integrations?)
    end
end

Configure OAuth owner lookup separately because the OAuth callback does not use the regular authenticated API session:

NeetoGoogleDriveEngine.oauth_owner_resolver = lambda do |user, owner_id|
  user.organization.forms.find(owner_id)
end

Never use an unscoped Form.find, Meeting.find, or other owner lookup in the controller override or OAuth resolver.

5. Install and render the frontend

Install the package:

yarn add @bigbinary/neeto-google-drive-frontend

Render the connection screen:

import { GoogleDriveIntegration } from "@bigbinary/neeto-google-drive-frontend";

const GoogleDriveConnection = ({ canManageIntegrations, formId }) => (
  <GoogleDriveIntegration
    canManageIntegrations={canManageIntegrations}
    helpUrl="https://help.neetoform.com/google-drive"
    managePath={`/admin/form/${formId}/settings/integrations/google-drive/manage`}
    ownerId={formId}
    resourceName="submission"
    resourceNamePlural="submissions"
  />
);

Render the settings screen:

import { GoogleDriveSettings } from "@bigbinary/neeto-google-drive-frontend";

const GoogleDriveManage = ({
  canManageIntegrations,
  formId,
  navigateToIntegration,
}) => (
  <GoogleDriveSettings
    canManageIntegrations={canManageIntegrations}
    ownerId={formId}
    resourceName="submission"
    renderAdditionalSettings={FormGoogleDriveAdditionalSettings}
    renderMissingIntegration={() => <MissingIntegration />}
    onCancel={navigateToIntegration}
    onSave={navigateToIntegration}
  />
);

GoogleDriveIntegration requires resourceName and resourceNamePlural. GoogleDriveSettings requires only resourceName. Pass "booking" / "bookings" to the integration and "booking" to the settings in neetoCal.

renderAdditionalSettings is optional. Pass it only when the product needs extra options. The component receives Formik props plus additionalSettingsData from the owner. Read and write host values under values.additionalSettings (for example saveResourcePdf or selectedAttachmentFieldIds).

Products that do not need extra options, such as a first neetoCal version, omit renderAdditionalSettings and get only the shared folder settings.

The host must load the nano's neetoGoogleDrive translations into its i18next resources.

Backend API

The mounted engine exposes:

MethodEndpointPurpose
GET/neeto_google_drive/api/v1/google_drive/:owner_idConnection state, authorization URL, settings, and fields
PATCH/neeto_google_drive/api/v1/google_drive/:owner_idUpdate settings and rename the connected main folder
DELETE/neeto_google_drive/api/v1/google_drive/:owner_idDisconnect without deleting Drive files
GET/neeto_google_drive/api/v1/oauthGoogle OAuth callback

The GET response contains:

{
  "authorizationUrl": "https://accounts.google.com/...",
  "connected": true,
  "connectedEmail": "[email protected]",
  "folderUrl": "https://drive.google.com/drive/folders/...",
  "error": "",
  "settings": {
    "folderName": "Customer feedback",
    "createResourceFolder": true,
    "resourceFolderNameFields": ["full_name", "submission_date"],
    "additionalSettings": {
      "selectedAttachmentFieldIds": ["resume"],
      "saveResourcePdf": true
    }
  },
  "namingFields": [],
  "additionalSettingsData": {
    "attachmentFields": [{ "id": "resume", "label": "Resume" }]
  }
}

additionalSettings and additionalSettingsData are host-owned. The nano persists and returns them without interpreting their keys.

The exact JSON key casing follows the host application's response transformation.

Data owned by the engine

NeetoGoogleDriveEngine::GoogleDrive stores:

  • Polymorphic owner.
  • Active or inactive status.
  • Connected Google account UID and email.
  • Main-folder ID and name.
  • Export settings and the latest authorization error.

NeetoGoogleDriveEngine::Credential stores:

  • Encrypted access token.
  • Encrypted refresh token.
  • Token expiry time.
  • One-to-one link to the integration.

google_drive.export_configuration returns a JSON-safe settings snapshot for a background job:

{
  "create_resource_folder" => true,
  "resource_folder_name_fields" => ["full_name", "submission_date"],
  "additional_settings" => {
    "selected_attachment_field_ids" => ["resume"],
    "save_resource_pdf" => true
  }
}

The host job reads product-specific keys from additional_settings. Pass this snapshot and the current credential ID to the job. The credential ID lets a stale queued job stop after the owner disconnects or changes accounts.

Using the Drive client from a host exporter

The host exporter can use the nano-owned client:

client = NeetoGoogleDriveEngine::Client.new(
  owner.google_drive.credential
)

Available operations:

client.get_file(file_id)
client.create_folder(
  name: folder_name,
  parent_id: parent_id,
  app_properties: metadata
)
client.rename_file(file_id, name)
client.delete_file(file_id)
client.list_files(
  parent_id: parent_id,
  mime_type: mime_type,
  app_properties: metadata
)
client.upload_file(
  name: filename,
  parent_id: parent_id,
  upload_source: file.path,
  content_type: content_type,
  app_properties: metadata
)

Pass structured filters to list_files:

files = client.list_files(
  parent_id: target_folder.id,
  mime_type: NeetoGoogleDriveEngine::Client::FOLDER_MIME_TYPE,
  app_properties: {
    "neeto_google_drive_resource" => "submission_folder",
    "neeto_form_submission_id" => submission.id
  }
)

Do not construct Google Drive query strings in the host. The client escapes values and owns Google-specific query syntax.

Use nano-owned metadata keys for data shared across products:

metadata = NeetoGoogleDriveEngine::FileMetadata

{
  metadata::OWNER_ID_PROPERTY => owner.id,
  metadata::OWNER_TYPE_PROPERTY => owner.class.name,
  metadata::RESOURCE_PROPERTY => "main_folder"
}

Keep product-specific keys, such as neeto_form_submission_id, in the host product.

neetoForm example: implemented

neetoForm uses Form as the connection owner and Submission as the exported resource.

Model adapter

module GoogleDriveIntegrable
  extend ActiveSupport::Concern

  SUBMISSION_DATE_FIELD = "submission_date"
  SUBMISSION_ID_FIELD = "submission_id"
  ATTACHMENT_RECORD_KINDS =
    %w[file_upload take_photo digital_signature].freeze

  def google_drive_default_folder_name
    title
  end

  def google_drive_default_resource_folder_name_fields
    naming_records = answer_records.where.not(kind: ATTACHMENT_RECORD_KINDS)
    default_record =
      naming_records.find_by(kind: :full_name) || naming_records.first

    [default_record&.id&.to_s, SUBMISSION_DATE_FIELD].compact
  end

  def google_drive_naming_fields
    answer_records
      .where.not(kind: ATTACHMENT_RECORD_KINDS)
      .map do |record|
        {
          id: record.id.to_s,
          label: record.formatted_label,
          kind: record.kind
        }
      end
      .concat(
        [
          {
            id: SUBMISSION_DATE_FIELD,
            label: "Submission date",
            kind: "system"
          },
          {
            id: SUBMISSION_ID_FIELD,
            label: "Submission ID",
            kind: "system"
          }
        ]
      )
  end

  def google_drive_default_additional_settings
    {
      selected_attachment_field_ids: google_drive_attachment_fields.pluck(:id),
      save_resource_pdf: true
    }
  end

  def google_drive_additional_settings_data
    { attachment_fields: google_drive_attachment_fields }
  end

  def google_drive_attachment_fields
    answer_records
      .where(kind: ATTACHMENT_RECORD_KINDS)
      .map { |record| { id: record.id.to_s, label: record.formatted_label } }
  end

  def google_drive_redirect_url(query)
    url = URI(google_drive_integration_page_url)
    url.query = query.to_query
    url.to_s
  end
end

Attachment fields and the PDF toggle are Form-owned. The nano only stores them inside additional_settings and returns attachment field metadata through google_drive_additional_settings_data for Form's renderAdditionalSettings UI.

Background export

neetoForm snapshots the credential and settings when the submission completes:

if form.google_drive_exportable?
  google_drive = form.google_drive

  Integrations::GoogleDrive::SubmissionExporterJob.perform_async(
    submission.id,
    google_drive.credential.id,
    google_drive.export_configuration
  )
end

The host job owns:

  • Submission completion checks.
  • ActiveStorage attachment lookup.
  • Submission-folder naming.
  • Locale-aware PDF generation.
  • Retry scheduling and product logging.

neetoCal example: planned

This is a proposed adapter based on neetoCal's current model and route conventions. It is not implemented in neetoCal yet.

Use Meeting as the connection owner and Booking as the exported resource. Do not attach the connection to each Booking.

Planned initializer

NeetoGoogleDriveEngine.application_name = "NeetoCal"
NeetoGoogleDriveEngine.oauth_app_url =
  Rails.application.vault.google_drive[:oauth_app_url]
NeetoGoogleDriveEngine.oauth_client_id =
  Rails.application.vault.google_drive[:client_id]
NeetoGoogleDriveEngine.oauth_client_secret =
  Rails.application.vault.google_drive[:client_secret]
NeetoGoogleDriveEngine.oauth_state_private_key =
  Rails.application.vault.jwt[:connect_private_key]
NeetoGoogleDriveEngine.oauth_state_public_key =
  Rails.application.vault.jwt[:connect_public_key]
NeetoGoogleDriveEngine.user_class = "User"

Planned model adapter

module Meetings::GoogleDriveConcern
  extend ActiveSupport::Concern

  BOOKER_NAME_FIELD = "booker_name"
  BOOKING_DATE_FIELD = "booking_date"
  BOOKING_ID_FIELD = "booking_id"

  included do
    include NeetoGoogleDriveEngine::HasGoogleDrive
  end

  def google_drive_default_folder_name
    name
  end

  def google_drive_default_resource_folder_name_fields
    [BOOKER_NAME_FIELD, BOOKING_DATE_FIELD]
  end

  def google_drive_naming_fields
    [
      { id: BOOKER_NAME_FIELD, label: "Booker name", kind: "system" },
      { id: BOOKING_DATE_FIELD, label: "Booking date", kind: "system" },
      { id: BOOKING_ID_FIELD, label: "Booking ID", kind: "system" }
    ]
  end

  def google_drive_redirect_url(query)
    url = URI(
      "#{organization.root_url}/admin/scheduling-links/" \
        "#{sid}/settings/integrations/google-drive"
    )
    url.query = query.to_query
    url.to_s
  end
end

Planned controller configuration

Use neetoCal's organization scoping and existing Google Sheet permission until a dedicated Google Drive permission is introduced:

NeetoGoogleDriveEngine::Api::V1::BaseController.class_eval do
  private

    def load_owner
      @owner = @organization.meetings.find(params[:owner_id])
    end

    def authorize_google_drive!
      authorize(Meeting, :can_manage_google_sheet?)
    end
end
NeetoGoogleDriveEngine.oauth_owner_resolver = lambda do |user, owner_id|
  user.organization.meetings.find(owner_id)
end

Planned frontend adapter

import {
  GoogleDriveIntegration,
  GoogleDriveSettings,
} from "@bigbinary/neeto-google-drive-frontend";

const BookingDriveConnection = ({
  canManageGoogleSheet,
  managePath,
  meetingId,
}) => (
  <GoogleDriveIntegration
    canManageIntegrations={canManageGoogleSheet}
    managePath={managePath}
    ownerId={meetingId}
    resourceName="booking"
    resourceNamePlural="bookings"
  />
);

const BookingDriveSettings = ({
  canManageGoogleSheet,
  meetingId,
  navigateToIntegration,
}) => (
  <GoogleDriveSettings
    canManageIntegrations={canManageGoogleSheet}
    ownerId={meetingId}
    resourceName="booking"
    onCancel={navigateToIntegration}
    onSave={navigateToIntegration}
  />
);

Omit renderAdditionalSettings until Cal needs product-specific options. Connection copy uses resourceName / resourceNamePlural; settings labels use resourceName.

When neetoCal adds booking files or a booking PDF, render those controls in a Cal-owned renderAdditionalSettings component, store their values in additional_settings, and implement the export logic in neetoCal.

Frontend props

GoogleDriveIntegration

PropRequiredPurpose
ownerIdYesID of the model that owns the integration
canManageIntegrationsYesEnables the integration query for authorized users
managePathYesHost route opened by Manage Google Drive
resourceNameYesSingular UI noun
resourceNamePluralYesPlural UI noun
helpUrlNoLearn-more link

GoogleDriveSettings

PropRequiredPurpose
ownerIdYesID of the model that owns the integration
canManageIntegrationsYesEnables the settings query for authorized users
onCancelYesHost navigation after Cancel
onSaveNoHost navigation after a successful save
renderMissingIntegrationNoHost UI when the owner is disconnected
renderAdditionalSettingsNoHost component for product-specific options
resourceNameYesSingular noun used in settings labels

useGoogleDrive

Use the hook when the host only needs connection status:

const { isConnected, isLoading } = useGoogleDrive({
  ownerId: meetingId,
  canManageIntegrations: canManageGoogleSheet,
});

It also returns update, disconnect, loading, and disconnect-dialog state.

Connection and folder behavior

Connect

  1. The UI fetches a signed Google authorization URL.
  2. Google redirects to the engine OAuth callback.
  3. The callback verifies state, scopes, user, and tenant-scoped owner.
  4. The engine stores encrypted credentials for that owner.
  5. The engine creates or restores the owner's main Drive folder.

Reconnect

  • Reconnecting the same account preserves settings and the main-folder ID.
  • An omitted refresh token is reused only for the same Google account UID.
  • Connecting another account clears the old folder ID.
  • The new account receives its own main folder.

Disconnect

  • The encrypted credential is destroyed.
  • The integration becomes inactive.
  • Settings and folder metadata remain stored.
  • Existing Google Drive folders and files are not deleted.
  • No reconnect email is sent.

Error handling

The nano exposes reusable error categories:

NeetoGoogleDriveEngine::AUTHORIZATION_ERRORS
NeetoGoogleDriveEngine::TRANSIENT_ERRORS
NeetoGoogleDriveEngine::EXPORT_MAX_ATTEMPTS

A host job can use them like this:

def perform
  export_resource!
rescue *NeetoGoogleDriveEngine::TRANSIENT_ERRORS => exception
  raise TransientError.new(exception)
rescue *NeetoGoogleDriveEngine::AUTHORIZATION_ERRORS
  NeetoGoogleDriveEngine::DisconnectService.new(
    google_drive,
    error: "authorization_expired"
  ).process!
end

The nano stores the error for the connection UI. User notification channels remain host-owned.

Testing

Run the backend suite:

bundle exec rails test

Build the frontend package:

yarn build

The backend suite covers:

  • Integration and credential models.
  • OAuth state and token exchange.
  • Same-account and different-account reconnects.
  • Drive query escaping and token refresh.
  • Main-folder creation, recovery, rename, and concurrency behavior.

Host products should separately test their authorization overrides, export job, resource formatter, attachments, and PDFs.

Local frontend development

Follow the frontend package development guide to build and consume the package locally.

Publishing

Follow the building and releasing packages guide.

版本与发布记录

@bigbinary/neeto-google-drive-frontend 共发布 17 个版本,首次发布于 2026/07/30;过去 12 个月发布了 17 个版本。

版本发布日期距今
2.0.16latest2026/10/011 个月前
2.0.152026/08/142 个月前
2.0.142026/08/142 个月前
2.0.132026/08/132 个月前
2.0.122026/08/122 个月前
2.0.112026/08/122 个月前

关于 @bigbinary/neeto-google-drive-frontend 的常见问题

@bigbinary/neeto-google-drive-frontend 是什么?

Reusable Google Drive integration for Neeto products.

如何安装 @bigbinary/neeto-google-drive-frontend?

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

@bigbinary/neeto-google-drive-frontend 支持 TypeScript 吗?

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

@bigbinary/neeto-google-drive-frontend 支持 ESM 还是 CommonJS?

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

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

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

@bigbinary/neeto-google-drive-frontend 可以商用吗?

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

@bigbinary/neeto-google-drive-frontend 的下载量有多少?

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

@bigbinary/neeto-google-drive-frontend 还在维护吗?

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