@tulip-systems/drive-local 0.11.1

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.
Files changed (61) hide show
  1. package/LICENSE +662 -0
  2. package/dist/client.d.mts +12 -0
  3. package/dist/client.mjs +12 -0
  4. package/dist/database/drizzle/lib/adapter.d.mts +310 -0
  5. package/dist/database/drizzle/lib/adapter.mjs +520 -0
  6. package/dist/database/drizzle/lib/compilers.d.mts +395 -0
  7. package/dist/database/drizzle/lib/compilers.mjs +21 -0
  8. package/dist/database/drizzle/lib/schema.d.mts +61 -0
  9. package/dist/drizzle.d.mts +4 -0
  10. package/dist/drizzle.mjs +3 -0
  11. package/dist/index.d.mts +8 -0
  12. package/dist/index.mjs +8 -0
  13. package/dist/root/components/command-file-update.d.mts +11 -0
  14. package/dist/root/components/command-file-update.mjs +44 -0
  15. package/dist/root/components/command-file-upload.d.mts +5 -0
  16. package/dist/root/components/command-file-upload.mjs +31 -0
  17. package/dist/root/components/command-folder-create.d.mts +11 -0
  18. package/dist/root/components/command-folder-create.mjs +50 -0
  19. package/dist/root/components/command-folder-update.d.mts +11 -0
  20. package/dist/root/components/command-folder-update.mjs +44 -0
  21. package/dist/root/components/content.client.d.mts +5 -0
  22. package/dist/root/components/content.client.mjs +5 -0
  23. package/dist/root/components/navigation.client.d.mts +11 -0
  24. package/dist/root/components/navigation.client.mjs +12 -0
  25. package/dist/root/components/provider.client.d.mts +16 -0
  26. package/dist/root/components/provider.client.mjs +65 -0
  27. package/dist/root/components/upload-zone-context.client.d.mts +36 -0
  28. package/dist/root/components/upload-zone-context.client.mjs +19 -0
  29. package/dist/root/components/upload-zone.client.d.mts +16 -0
  30. package/dist/root/components/upload-zone.client.mjs +147 -0
  31. package/dist/root/components/view.client.d.mts +20 -0
  32. package/dist/root/components/view.client.mjs +86 -0
  33. package/dist/root/config/columns-data.d.mts +6 -0
  34. package/dist/root/config/columns-data.mjs +62 -0
  35. package/dist/root/config/filters.d.mts +404 -0
  36. package/dist/root/config/filters.mjs +122 -0
  37. package/dist/root/config/sorting.d.mts +38 -0
  38. package/dist/root/config/sorting.mjs +26 -0
  39. package/dist/root/lib/constants.d.mts +12 -0
  40. package/dist/root/lib/constants.mjs +27 -0
  41. package/dist/root/lib/database/contracts.d.mts +112 -0
  42. package/dist/root/lib/database/filters.d.mts +28 -0
  43. package/dist/root/lib/database/filters.mjs +73 -0
  44. package/dist/root/lib/helpers.d.mts +33 -0
  45. package/dist/root/lib/helpers.mjs +78 -0
  46. package/dist/root/lib/route-handler.server.d.mts +36 -0
  47. package/dist/root/lib/route-handler.server.mjs +111 -0
  48. package/dist/root/lib/router.server.d.mts +819 -0
  49. package/dist/root/lib/router.server.mjs +87 -0
  50. package/dist/root/lib/search-params.d.mts +15 -0
  51. package/dist/root/lib/search-params.mjs +6 -0
  52. package/dist/root/lib/service.server.d.mts +522 -0
  53. package/dist/root/lib/service.server.mjs +613 -0
  54. package/dist/root/lib/upload.client.d.mts +60 -0
  55. package/dist/root/lib/upload.client.mjs +97 -0
  56. package/dist/root/lib/validators.d.mts +710 -0
  57. package/dist/root/lib/validators.mjs +116 -0
  58. package/dist/server.d.mts +5 -0
  59. package/dist/server.mjs +4 -0
  60. package/package.json +83 -0
  61. package/styles.css +1 -0
@@ -0,0 +1,112 @@
1
+ import { LocalDriveFiltersSchema, LocalDrivePresignedUrlFiltersSchema, LocalDriveVariantFiltersSchema } from "../../config/filters.mjs";
2
+ import { LocalDriveTableSortsSchema } from "../../config/sorting.mjs";
3
+ import { ImageVariant } from "../constants.mjs";
4
+ import { LocalNode } from "../validators.mjs";
5
+ import { LocalDriveDatabaseNodeFiltersSchema } from "./filters.mjs";
6
+ import { SelectStorageAssetSchema } from "@tulip-systems/storage";
7
+ //#region src/root/lib/database/contracts.d.ts
8
+ type LocalDriveDatabaseNodeWithAsset = LocalNode & {
9
+ asset: SelectStorageAssetSchema | null;
10
+ };
11
+ type LocalDriveDatabaseListResult<TData> = {
12
+ data: TData[];
13
+ total: number;
14
+ };
15
+ type LocalDriveDatabaseListNodesWithAssetInput = {
16
+ filters: LocalDriveFiltersSchema;
17
+ sorts?: LocalDriveTableSortsSchema;
18
+ limit: number;
19
+ offset: number;
20
+ };
21
+ type LocalDriveDatabaseFindFirstNodeInput = {
22
+ filters?: LocalDriveDatabaseNodeFiltersSchema;
23
+ };
24
+ type LocalDriveDatabaseFindNodesInput = {
25
+ filters?: LocalDriveDatabaseNodeFiltersSchema;
26
+ sorts?: LocalDriveTableSortsSchema;
27
+ limit?: number;
28
+ offset?: number;
29
+ };
30
+ type LocalDriveDatabaseNodeParent = Pick<LocalNode, "id" | "name" | "parentId"> & {
31
+ depth: number;
32
+ };
33
+ type LocalDriveDatabaseNodeChild = LocalNode & {
34
+ depth: number;
35
+ };
36
+ type LocalDriveDatabasePresignedUrl = {
37
+ url: string;
38
+ expiresAt: Date;
39
+ };
40
+ type LocalDriveDatabaseNodeVariant = {
41
+ id: string;
42
+ createdAt: Date;
43
+ updatedAt: Date;
44
+ nodeId: string;
45
+ assetId: string;
46
+ variant: ImageVariant;
47
+ width: number;
48
+ };
49
+ type LocalDriveDatabaseFindVariantsInput = {
50
+ filters?: LocalDriveVariantFiltersSchema;
51
+ limit?: number;
52
+ offset?: number;
53
+ };
54
+ type LocalDriveDatabaseFindFirstPresignedUrlInput = {
55
+ filters?: LocalDrivePresignedUrlFiltersSchema;
56
+ };
57
+ type LocalDriveDatabaseUpdateNodeInput = Partial<Pick<LocalNode, "archivedAt" | "contentType" | "hidden" | "name" | "parentId" | "readonly" | "size">>;
58
+ type LocalDriveDatabaseUpdateNodesInput = {
59
+ filters: LocalDriveDatabaseNodeFiltersSchema;
60
+ data: LocalDriveDatabaseUpdateNodeInput;
61
+ };
62
+ type LocalDriveDatabaseDeleteNodesInput = {
63
+ filters: LocalDriveDatabaseNodeFiltersSchema;
64
+ };
65
+ type LocalDriveDatabaseCreateNodeInput = {
66
+ type: Exclude<LocalNode["type"], null>;
67
+ name: string;
68
+ namespace: string;
69
+ parentId?: string | null;
70
+ size?: number | null;
71
+ contentType?: string | null;
72
+ hidden?: boolean;
73
+ readonly?: boolean;
74
+ subtype?: LocalNode["subtype"];
75
+ assetId?: string | null;
76
+ };
77
+ type UpsertLocalDrivePresignedUrlInput = {
78
+ nodeId: string;
79
+ url: string;
80
+ variant: ImageVariant;
81
+ variantId?: string | null;
82
+ disposition: "inline" | "attachment";
83
+ expiresAt: Date;
84
+ };
85
+ type LocalDriveDatabaseCreateVariantInput = {
86
+ nodeId: string;
87
+ assetId: string;
88
+ variant: ImageVariant;
89
+ width: number;
90
+ };
91
+ interface LocalDriveDatabaseProvider {
92
+ findNodeById(id: string): Promise<LocalNode | null>;
93
+ findFirstNode(input?: LocalDriveDatabaseFindFirstNodeInput): Promise<LocalNode | null>;
94
+ findNodes(input?: LocalDriveDatabaseFindNodesInput): Promise<LocalNode[]>;
95
+ listNodesWithAsset(input: LocalDriveDatabaseListNodesWithAssetInput): Promise<LocalDriveDatabaseListResult<LocalDriveDatabaseNodeWithAsset>>;
96
+ getNodeParents(input: {
97
+ id: string | null;
98
+ namespace: string;
99
+ }): Promise<LocalDriveDatabaseNodeParent[]>;
100
+ getNodeChildren(ids: string[]): Promise<LocalDriveDatabaseNodeChild[]>;
101
+ createNode(input: LocalDriveDatabaseCreateNodeInput): Promise<LocalNode | null>;
102
+ updateNodeById(id: string, data: LocalDriveDatabaseUpdateNodeInput): Promise<LocalNode | null>;
103
+ updateNodes(input: LocalDriveDatabaseUpdateNodesInput): Promise<LocalNode[]>;
104
+ deleteNodeById(id: string): Promise<void>;
105
+ deleteNodes(input: LocalDriveDatabaseDeleteNodesInput): Promise<void>;
106
+ findVariants(input?: LocalDriveDatabaseFindVariantsInput): Promise<LocalDriveDatabaseNodeVariant[]>;
107
+ createVariant(input: LocalDriveDatabaseCreateVariantInput): Promise<void>;
108
+ findFirstPresignedUrl(input?: LocalDriveDatabaseFindFirstPresignedUrlInput): Promise<LocalDriveDatabasePresignedUrl | null>;
109
+ upsertPresignedUrl(input: UpsertLocalDrivePresignedUrlInput): Promise<void>;
110
+ }
111
+ //#endregion
112
+ export { LocalDriveDatabaseCreateNodeInput, LocalDriveDatabaseCreateVariantInput, LocalDriveDatabaseDeleteNodesInput, LocalDriveDatabaseFindFirstNodeInput, LocalDriveDatabaseFindFirstPresignedUrlInput, LocalDriveDatabaseFindNodesInput, LocalDriveDatabaseFindVariantsInput, LocalDriveDatabaseListNodesWithAssetInput, LocalDriveDatabaseListResult, LocalDriveDatabaseNodeChild, LocalDriveDatabaseNodeParent, LocalDriveDatabaseNodeVariant, LocalDriveDatabaseNodeWithAsset, LocalDriveDatabasePresignedUrl, LocalDriveDatabaseProvider, LocalDriveDatabaseUpdateNodeInput, LocalDriveDatabaseUpdateNodesInput, UpsertLocalDrivePresignedUrlInput };
@@ -0,0 +1,28 @@
1
+ import { z as z$1 } from "zod";
2
+ //#region src/root/lib/database/filters.d.ts
3
+ declare const localDriveDatabaseNodeFiltersSchema: z$1.ZodObject<{
4
+ search: z$1.ZodOptional<z$1.ZodString>;
5
+ types: z$1.ZodOptional<z$1.ZodArray<z$1.ZodEnum<{
6
+ readonly folder: "folder";
7
+ readonly file: "file";
8
+ }>>>;
9
+ contentTypes: z$1.ZodOptional<z$1.ZodArray<z$1.ZodString>>;
10
+ nodeIds: z$1.ZodOptional<z$1.ZodArray<z$1.ZodString>>;
11
+ assetIds: z$1.ZodOptional<z$1.ZodArray<z$1.ZodString>>;
12
+ namespace: z$1.ZodOptional<z$1.ZodString>;
13
+ parentId: z$1.ZodOptional<z$1.ZodNullable<z$1.ZodString>>;
14
+ subtypes: z$1.ZodOptional<z$1.ZodArray<z$1.ZodEnum<{
15
+ readonly image: "image";
16
+ readonly document: "document";
17
+ readonly spreadsheet: "spreadsheet";
18
+ readonly video: "video";
19
+ readonly audio: "audio";
20
+ readonly archive: "archive";
21
+ readonly other: "other";
22
+ }>>>;
23
+ isArchived: z$1.ZodOptional<z$1.ZodBoolean>;
24
+ hidden: z$1.ZodOptional<z$1.ZodBoolean>;
25
+ }, z$1.core.$strip>;
26
+ type LocalDriveDatabaseNodeFiltersSchema = z$1.infer<typeof localDriveDatabaseNodeFiltersSchema>;
27
+ //#endregion
28
+ export { LocalDriveDatabaseNodeFiltersSchema, localDriveDatabaseNodeFiltersSchema };
@@ -0,0 +1,73 @@
1
+ import { nodeSubtypes } from "../constants.mjs";
2
+ import { DRIVE_NODE_TYPES } from "@tulip-systems/drive";
3
+ import { arrayFilter, booleanFilter, createFilteringParser, defineFilters, enumFilter, resolveFiltersSchema, stringFilter } from "@tulip-systems/query";
4
+ import { z as z$1 } from "zod";
5
+ //#region src/root/lib/database/filters.ts
6
+ /**
7
+ * Database node filters.
8
+ *
9
+ * These intentionally do not apply lifecycle defaults. Public list filters can
10
+ * default to visible, non-archived nodes, but database mutations and direct
11
+ * lookups must only filter lifecycle state when explicitly requested.
12
+ */
13
+ const localDriveDatabaseNodeFilters = defineFilters({
14
+ search: stringFilter.build((value) => value ? {
15
+ field: "name",
16
+ operator: "ilike",
17
+ value: `%${value}%`
18
+ } : null),
19
+ types: arrayFilter(enumFilter(DRIVE_NODE_TYPES)).build((value) => value?.length ? {
20
+ field: "type",
21
+ operator: "in",
22
+ value
23
+ } : null),
24
+ contentTypes: arrayFilter(stringFilter).build((value) => value?.length ? {
25
+ field: "contentType",
26
+ operator: "in",
27
+ value
28
+ } : null),
29
+ nodeIds: arrayFilter(stringFilter).build((value) => value === void 0 ? null : {
30
+ field: "id",
31
+ operator: "in",
32
+ value
33
+ }),
34
+ assetIds: arrayFilter(stringFilter).build((value) => value === void 0 ? null : {
35
+ field: "assetId",
36
+ operator: "in",
37
+ value
38
+ }),
39
+ namespace: stringFilter.build((value) => value ? {
40
+ field: "namespace",
41
+ operator: "eq",
42
+ value
43
+ } : null),
44
+ parentId: stringFilter.options({ schema: z$1.string().nullable() }).build((value) => {
45
+ if (value === void 0) return null;
46
+ return value === null ? {
47
+ field: "parentId",
48
+ operator: "isNull"
49
+ } : {
50
+ field: "parentId",
51
+ operator: "eq",
52
+ value
53
+ };
54
+ }),
55
+ subtypes: arrayFilter(enumFilter(nodeSubtypes)).build((value) => value?.length ? {
56
+ field: "subtype",
57
+ operator: "in",
58
+ value
59
+ } : null),
60
+ isArchived: booleanFilter.build((value) => value === void 0 ? null : {
61
+ field: "archivedAt",
62
+ operator: value ? "isNotNull" : "isNull"
63
+ }),
64
+ hidden: booleanFilter.build((value) => value === void 0 ? null : {
65
+ field: "hidden",
66
+ operator: "eq",
67
+ value
68
+ })
69
+ });
70
+ resolveFiltersSchema(localDriveDatabaseNodeFilters);
71
+ const localDriveDatabaseNodeFiltersParser = createFilteringParser(localDriveDatabaseNodeFilters);
72
+ //#endregion
73
+ export { localDriveDatabaseNodeFilters, localDriveDatabaseNodeFiltersParser };
@@ -0,0 +1,33 @@
1
+ import { LocalDriveNodeSubtype } from "./constants.mjs";
2
+ import { GetLocalFileURLSchema, LocalDriveNode, LocalNode } from "./validators.mjs";
3
+ import { ImageLoaderProps } from "next/image";
4
+ //#region src/root/lib/helpers.d.ts
5
+ /**
6
+ * Convert a LocalNode to LocalDriveNode by adding provider and links
7
+ * @param node The LocalNode to convert
8
+ * @returns The converted LocalDriveNode
9
+ */
10
+ declare function toLocalDriveNode<TNode extends LocalNode>(node: TNode): LocalDriveNode;
11
+ /**
12
+ * Check if the node is a file
13
+ */
14
+ declare function isLocalDriveFile(node: Pick<LocalNode, "type">): node is LocalNode;
15
+ /**
16
+ * Check if the node is a folder
17
+ */
18
+ declare function isLocalDriveFolder(node: Pick<LocalNode, "type">): node is LocalNode;
19
+ /**
20
+ * Get file url
21
+ */
22
+ declare function getLocalDriveFileUrl(id: string, options?: Partial<GetLocalFileURLSchema>): string;
23
+ /**
24
+ * Image loader
25
+ */
26
+ declare function localDriveImageLoader({ src, width }: ImageLoaderProps): string;
27
+ declare function inferLocalDriveNodeSubtype(input: Partial<Pick<LocalDriveNode, "name" | "contentType">>): LocalDriveNodeSubtype;
28
+ /**
29
+ * Render bytes
30
+ */
31
+ declare function renderBytes(bytes: number): string;
32
+ //#endregion
33
+ export { getLocalDriveFileUrl, inferLocalDriveNodeSubtype, isLocalDriveFile, isLocalDriveFolder, localDriveImageLoader, renderBytes, toLocalDriveNode };
@@ -0,0 +1,78 @@
1
+ import { inferDriveNodeSubtype } from "@tulip-systems/drive";
2
+ //#region src/root/lib/helpers.ts
3
+ /**
4
+ * Convert a LocalNode to LocalDriveNode by adding provider and links
5
+ * @param node The LocalNode to convert
6
+ * @returns The converted LocalDriveNode
7
+ */
8
+ function toLocalDriveNode(node) {
9
+ return {
10
+ ...node,
11
+ type: node.type,
12
+ readonly: node.readonly ?? false,
13
+ hidden: node.hidden ?? false,
14
+ provider: "local",
15
+ links: {
16
+ view: node.type === "file" ? getLocalDriveFileUrl(node.id, { disposition: "inline" }) : null,
17
+ download: node.type === "file" ? getLocalDriveFileUrl(node.id, { disposition: "attachment" }) : null,
18
+ preview: node.type === "file" ? getLocalDriveFileUrl(node.id) : null,
19
+ thumbnail: node.type === "file" ? getLocalDriveFileUrl(node.id, { variant: "preview-256" }) : null
20
+ },
21
+ availability: "ready"
22
+ };
23
+ }
24
+ /**
25
+ * Check if the node is a file
26
+ */
27
+ function isLocalDriveFile(node) {
28
+ return node.type === "file";
29
+ }
30
+ /**
31
+ * Check if the node is a folder
32
+ */
33
+ function isLocalDriveFolder(node) {
34
+ return node.type === "folder";
35
+ }
36
+ /**
37
+ * Get file url
38
+ */
39
+ function getLocalDriveFileUrl(id, options = {}) {
40
+ const searchParams = new URLSearchParams();
41
+ if (options?.variant) searchParams.set("variant", options.variant);
42
+ if (options?.disposition) searchParams.set("disposition", options.disposition);
43
+ const queryString = searchParams.toString();
44
+ return `/api/drive/files/${id}${queryString ? `?${queryString}` : ""}`;
45
+ }
46
+ /**
47
+ * Image loader
48
+ */
49
+ function localDriveImageLoader({ src, width }) {
50
+ const url = new URL(src, window.location.origin);
51
+ url.searchParams.set("variant", `preview-${width}`);
52
+ return url.toString();
53
+ }
54
+ function inferLocalDriveNodeSubtype(input) {
55
+ return inferDriveNodeSubtype(input);
56
+ }
57
+ /**
58
+ * Render bytes
59
+ */
60
+ function renderBytes(bytes) {
61
+ const units = [
62
+ "B",
63
+ "KB",
64
+ "MB",
65
+ "GB",
66
+ "TB",
67
+ "PB"
68
+ ];
69
+ let size = bytes;
70
+ let unitIndex = 0;
71
+ while (size >= 1024 && unitIndex < units.length - 1) {
72
+ size /= 1024;
73
+ unitIndex++;
74
+ }
75
+ return `${size.toFixed(2)}${units[unitIndex]}`;
76
+ }
77
+ //#endregion
78
+ export { getLocalDriveFileUrl, inferLocalDriveNodeSubtype, isLocalDriveFile, isLocalDriveFolder, localDriveImageLoader, renderBytes, toLocalDriveNode };
@@ -0,0 +1,36 @@
1
+ import { LocalDrive } from "./service.server.mjs";
2
+ import { NextRequest } from "next/server";
3
+ import { AuthServer, AuthServerSessionCapability } from "@tulip-systems/auth";
4
+ //#region src/root/lib/route-handler.server.d.ts
5
+ type RouteCtx = {
6
+ params: Promise<{
7
+ rest?: string[];
8
+ }>;
9
+ };
10
+ type AuthWithSession = AuthServer<{
11
+ capabilities: [AuthServerSessionCapability];
12
+ }>;
13
+ type CreateLocalDriveRouteHandlerProps<TAuth extends AuthWithSession> = {
14
+ auth: TAuth;
15
+ drive: LocalDrive;
16
+ };
17
+ /**
18
+ * Creates a catch-all drive route handler for `/api/drive/[[...rest]]`.
19
+ *
20
+ * Current support:
21
+ * - `GET /api/drive/files/:id?variant=:variant&disposition=:disposition`
22
+ * resolves a drive node, checks access for private local assets, and redirects
23
+ * to a short-lived file URL for the requested node variant.
24
+ *
25
+ * @param props - Route handler dependencies.
26
+ * @returns Next.js route handlers for GET, POST, PUT, PATCH, and DELETE.
27
+ */
28
+ declare function createLocalDriveRouteHandler<TAuth extends AuthWithSession>(context: CreateLocalDriveRouteHandlerProps<TAuth>): {
29
+ GET: (request: NextRequest, ctx: RouteCtx) => Promise<Response>;
30
+ POST: () => Promise<Response>;
31
+ PUT: () => Promise<Response>;
32
+ PATCH: () => Promise<Response>;
33
+ DELETE: () => Promise<Response>;
34
+ };
35
+ //#endregion
36
+ export { createLocalDriveRouteHandler };
@@ -0,0 +1,111 @@
1
+ import { getLocalFileURLSchema } from "./validators.mjs";
2
+ import z from "zod";
3
+ import { ORPCError } from "@orpc/server";
4
+ import { getSession } from "@tulip-systems/auth/next/server";
5
+ import { connection } from "next/server";
6
+ //#region src/root/lib/route-handler.server.ts
7
+ /**
8
+ * Creates a catch-all drive route handler for `/api/drive/[[...rest]]`.
9
+ *
10
+ * Current support:
11
+ * - `GET /api/drive/files/:id?variant=:variant&disposition=:disposition`
12
+ * resolves a drive node, checks access for private local assets, and redirects
13
+ * to a short-lived file URL for the requested node variant.
14
+ *
15
+ * @param props - Route handler dependencies.
16
+ * @returns Next.js route handlers for GET, POST, PUT, PATCH, and DELETE.
17
+ */
18
+ function createLocalDriveRouteHandler(context) {
19
+ /**
20
+ * GET /api/drive/[[...rest]]
21
+ *
22
+ * Current route support:
23
+ * - /api/drive/files/:id?variant=:variant&disposition=:disposition
24
+ */
25
+ async function GET(request, ctx) {
26
+ const { rest = [] } = await ctx.params;
27
+ if (rest[0] === "files") {
28
+ const id = rest[1];
29
+ if (!id) return Response.json({ error: {
30
+ code: "BAD_REQUEST",
31
+ message: "Missing file id"
32
+ } }, { status: 400 });
33
+ const searchParams = request.nextUrl.searchParams;
34
+ const variant = searchParams.get("variant") ?? void 0;
35
+ const disposition = searchParams.get("disposition") ?? void 0;
36
+ try {
37
+ const node = await context.drive.getNodeById(id);
38
+ if (!node) return Response.json({ error: {
39
+ code: "NOT_FOUND",
40
+ message: "Node not found"
41
+ } }, { status: 404 });
42
+ if (node.assetId) {
43
+ const asset = await context.drive.storage.getAssetById(node.assetId);
44
+ if (!asset) return Response.json({ error: {
45
+ code: "NOT_FOUND",
46
+ message: "Asset not found"
47
+ } }, { status: 404 });
48
+ if (asset.visibility === "private") {
49
+ if (!await getSession(context.auth)) return Response.json({ error: {
50
+ code: "UNAUTHORIZED",
51
+ message: "Unauthorized"
52
+ } }, { status: 401 });
53
+ }
54
+ }
55
+ const options = getLocalFileURLSchema.parse({
56
+ variant,
57
+ disposition
58
+ });
59
+ const url = await context.drive.getURL(node, options);
60
+ return Response.redirect(url, 307);
61
+ } catch (error) {
62
+ if (error instanceof z.ZodError) return Response.json({ error: {
63
+ code: "BAD_REQUEST",
64
+ message: "Invalid request input"
65
+ } }, { status: 400 });
66
+ if (error instanceof ORPCError) {
67
+ if (error.code === "BAD_REQUEST") return Response.json({ error: {
68
+ code: "BAD_REQUEST",
69
+ message: error.message
70
+ } }, { status: 400 });
71
+ if (error.code === "NOT_FOUND") return Response.json({ error: {
72
+ code: "NOT_FOUND",
73
+ message: error.message
74
+ } }, { status: 404 });
75
+ if (error.code === "UNAUTHORIZED") return Response.json({ error: {
76
+ code: "UNAUTHORIZED",
77
+ message: error.message
78
+ } }, { status: 401 });
79
+ }
80
+ console.error("Drive route error", error);
81
+ return Response.json({ error: {
82
+ code: "INTERNAL_SERVER_ERROR",
83
+ message: "Something went wrong"
84
+ } }, { status: 500 });
85
+ }
86
+ }
87
+ return Response.json({ error: {
88
+ code: "NOT_FOUND",
89
+ message: "Route not found"
90
+ } }, { status: 404 });
91
+ }
92
+ /**
93
+ * POST, PUT, PATCH, DELETE /api/drive/[[...rest]]
94
+ */
95
+ async function POST() {
96
+ await connection();
97
+ return Response.json({ error: {
98
+ code: "NOT_FOUND",
99
+ message: "Route not found"
100
+ } }, { status: 404 });
101
+ }
102
+ return {
103
+ GET,
104
+ POST,
105
+ PUT: POST,
106
+ PATCH: POST,
107
+ DELETE: POST
108
+ };
109
+ }
110
+ //#endregion
111
+ export { createLocalDriveRouteHandler };