@muhgholy/next-drive 4.10.1 → 4.12.0

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.
package/README.md CHANGED
@@ -90,6 +90,9 @@ import "@muhgholy/next-drive/client/styles.css";
90
90
 
91
91
  Create `lib/drive.ts` to configure storage, security, and authentication:
92
92
 
93
+ > [!IMPORTANT]
94
+ > You **must** connect to your database (e.g., Mongoose) **before** calling `driveConfiguration`. The configuration initialization will fail if the database connection is not ready.
95
+
93
96
  ```typescript
94
97
  // lib/drive.ts
95
98
  import { driveConfiguration } from "@muhgholy/next-drive/server";
@@ -540,6 +543,40 @@ cors: {
540
543
 
541
544
  > When `credentials: true`, you must specify explicit origins (not `'*'`).
542
545
 
546
+ ### Drive Modes
547
+
548
+ Next Drive supports two operation modes:
549
+
550
+ 1. **NORMAL** (Default): Requires `information` callback to identify the user and set quota. Enforces security limits.
551
+ 2. **ROOT**: System/Admin mode. No authentication required by default (unless you provide `information`).
552
+
553
+ > [!WARNING]
554
+ > In both modes, ensure your database connection is active before initializing the configuration.
555
+
556
+ **Root Mode Configuration:**
557
+
558
+ ```typescript
559
+ driveConfiguration({
560
+ mode: 'ROOT', // Enable root mode
561
+ database: 'MONGOOSE',
562
+ apiUrl: '/api/drive',
563
+ storage: { path: '/var/data/drive' },
564
+ // Optional: Security defaults to 10GB limit and all mime types if omitted
565
+ security: {
566
+ maxUploadSizeInBytes: 10 * 1024 * 1024 * 1024, // 10GB
567
+ allowedMimeTypes: ['*/*']
568
+ }
569
+ });
570
+ ```
571
+
572
+ **Key differences in ROOT mode:**
573
+ - `information` callback is **optional**.
574
+ - If `information` is omitted:
575
+ - `key` is `null` (files owned by system).
576
+ - `quota` is unlimited.
577
+ - Default `security.maxUploadSizeInBytes` is **10GB**.
578
+ - Default `security.allowedMimeTypes` is `['*/*']` (all files allowed).
579
+
543
580
  ---
544
581
 
545
582
  ## Google Drive Integration
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import type { TDriveFile } from '../types/client';
3
3
  export declare const DriveFileChooser: (props: Readonly<{
4
- value: TDriveFile | TDriveFile[] | null;
4
+ value?: TDriveFile | TDriveFile[] | null;
5
5
  onChange: (files: TDriveFile | TDriveFile[] | null) => void;
6
6
  multiple?: boolean;
7
7
  accept?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"file-chooser.d.ts","sourceRoot":"","sources":["../../src/client/file-chooser.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAoD,MAAM,OAAO,CAAC;AACzE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAuWjD,eAAO,MAAM,gBAAgB,GAAI,OAAO,QAAQ,CAAC;IAC7C,KAAK,EAAE,UAAU,GAAG,UAAU,EAAE,GAAG,IAAI,CAAC;IACxC,QAAQ,EAAE,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,EAAE,GAAG,IAAI,KAAK,IAAI,CAAC;IAC5D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC,sBAgLD,CAAC"}
1
+ {"version":3,"file":"file-chooser.d.ts","sourceRoot":"","sources":["../../src/client/file-chooser.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAoD,MAAM,OAAO,CAAC;AACzE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAuWjD,eAAO,MAAM,gBAAgB,GAAI,OAAO,QAAQ,CAAC;IAC7C,KAAK,CAAC,EAAE,UAAU,GAAG,UAAU,EAAE,GAAG,IAAI,CAAC;IACzC,QAAQ,EAAE,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,EAAE,GAAG,IAAI,KAAK,IAAI,CAAC;IAC5D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC,sBAgLD,CAAC"}
@@ -3044,7 +3044,7 @@ var MobileSidebarSheet = () => {
3044
3044
  };
3045
3045
  var DriveFileChooser = (props) => {
3046
3046
  const {
3047
- value,
3047
+ value = null,
3048
3048
  onChange,
3049
3049
  multiple = false,
3050
3050
  accept,
@@ -3109,10 +3109,10 @@ var DriveFileChooser = (props) => {
3109
3109
  ) : (
3110
3110
  /* Selected Files Display */
3111
3111
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chunkTA6L5FYG_cjs.cn("nd:rounded-lg nd:border", error ? "nd:border-destructive" : "nd:border-border", disabled && "nd:opacity-50"), children: [
3112
- !multiple && displayFiles[0] && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "nd:flex nd:items-center nd:gap-3 nd:p-2.5", children: [
3113
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "nd:size-12 nd:rounded-lg nd:overflow-hidden nd:bg-muted/30 nd:flex nd:items-center nd:justify-center nd:shrink-0", children: displayFiles[0].file.mime.startsWith("image/") ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: createUrl(displayFiles[0]), alt: displayFiles[0].file.name, className: "nd:size-full nd:object-cover" }) : chunkTA6L5FYG_cjs.getFileIcon(displayFiles[0].file.mime, false, "nd:size-6 nd:text-muted-foreground") }),
3112
+ !multiple && displayFiles[0] && displayFiles[0].file && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "nd:flex nd:items-center nd:gap-3 nd:p-2.5", children: [
3113
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "nd:size-12 nd:rounded-lg nd:overflow-hidden nd:bg-muted/30 nd:flex nd:items-center nd:justify-center nd:shrink-0", children: displayFiles[0].file.mime?.startsWith("image/") ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: createUrl(displayFiles[0]), alt: displayFiles[0].file.name || "", className: "nd:size-full nd:object-cover" }) : chunkTA6L5FYG_cjs.getFileIcon(displayFiles[0].file.mime || "", false, "nd:size-6 nd:text-muted-foreground") }),
3114
3114
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "nd:flex-1 nd:min-w-0", children: [
3115
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "nd:text-sm nd:font-medium nd:truncate", children: displayFiles[0].file.name }),
3115
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "nd:text-sm nd:font-medium nd:truncate", children: displayFiles[0].file.name || "Unknown" }),
3116
3116
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "nd:text-xs nd:text-muted-foreground", children: displayFiles[0].file.mime || "File" })
3117
3117
  ] }),
3118
3118
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "nd:flex nd:items-center nd:gap-1 nd:shrink-0", children: [
@@ -3133,9 +3133,9 @@ var DriveFileChooser = (props) => {
3133
3133
  !disabled && /* @__PURE__ */ jsxRuntime.jsx(Button, { type: "button", variant: "ghost", size: "sm", className: "nd:h-7 nd:text-xs nd:text-muted-foreground", onClick: () => onChange([]), children: "Clear" })
3134
3134
  ] })
3135
3135
  ] }),
3136
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "nd:max-h-40 nd:overflow-y-auto nd:divide-y nd:divide-border/50", children: displayFiles.map((file) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "nd:flex nd:items-center nd:gap-2.5 nd:px-3 nd:py-2 nd:hover:bg-muted/20", children: [
3137
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "nd:size-8 nd:rounded nd:overflow-hidden nd:bg-muted/30 nd:flex nd:items-center nd:justify-center nd:shrink-0", children: file.file.mime.startsWith("image/") ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: createUrl(file), alt: file.file.name, className: "nd:size-full nd:object-cover" }) : chunkTA6L5FYG_cjs.getFileIcon(file.file.mime, false, "nd:size-4 nd:text-muted-foreground") }),
3138
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "nd:flex-1 nd:text-sm nd:truncate", children: file.file.name }),
3136
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "nd:max-h-40 nd:overflow-y-auto nd:divide-y nd:divide-border/50", children: displayFiles.filter((file) => file?.file).map((file) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "nd:flex nd:items-center nd:gap-2.5 nd:px-3 nd:py-2 nd:hover:bg-muted/20", children: [
3137
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "nd:size-8 nd:rounded nd:overflow-hidden nd:bg-muted/30 nd:flex nd:items-center nd:justify-center nd:shrink-0", children: file.file.mime?.startsWith("image/") ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: createUrl(file), alt: file.file.name || "", className: "nd:size-full nd:object-cover" }) : chunkTA6L5FYG_cjs.getFileIcon(file.file.mime || "", false, "nd:size-4 nd:text-muted-foreground") }),
3138
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "nd:flex-1 nd:text-sm nd:truncate", children: file.file.name || "Unknown" }),
3139
3139
  !disabled && /* @__PURE__ */ jsxRuntime.jsx(Button, { type: "button", variant: "ghost", size: "icon", className: "nd:size-7 nd:shrink-0", onClick: () => handleRemove(file.id), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "nd:size-3.5" }) })
3140
3140
  ] }, file.id)) })
3141
3141
  ] })