next-tinacms-dos 1.1.1 → 1.2.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
@@ -6,12 +6,12 @@ Manage **Digital Ocean Space media assets** in TinaCMS.
6
6
 
7
7
  ### With Yarn
8
8
  ```bash
9
- yarn add next-tinacms-dos
9
+ yarn add next-tinacms-dos @tinacms/auth
10
10
  ```
11
11
 
12
12
  ### With NPM
13
13
  ```bash
14
- npm install next-tinacms-dos
14
+ npm install next-tinacms-dos @tinacms/auth
15
15
  ```
16
16
 
17
17
  ## Connect with Digital Ocean Space
@@ -116,6 +116,7 @@ export default createMediaHandler({
116
116
  region: 'us-east-1',
117
117
  },
118
118
  bucket: process.env.NEXT_PUBLIC_SPACE_NAME || '',
119
+ mediaRoot: 'images',
119
120
  authorized: async (req, _res) => {
120
121
  if (process.env.NEXT_PUBLIC_USE_LOCAL_CLIENT === "1") {
121
122
  return true;
@@ -8,7 +8,6 @@ export declare class DOSMediaStore implements MediaStore {
8
8
  persist(media: MediaUploadOptions[]): Promise<Media[]>;
9
9
  delete(media: Media): Promise<void>;
10
10
  list(options: MediaListOptions): Promise<MediaList>;
11
- previewSrc: (publicId: string | Media) => string;
12
11
  parse: (img: any) => any;
13
12
  private buildQuery;
14
13
  }
@@ -6,6 +6,7 @@ import { NextApiRequest, NextApiResponse } from 'next';
6
6
  export interface DOSConfig {
7
7
  config: S3ClientConfig;
8
8
  bucket: string;
9
+ mediaRoot?: string;
9
10
  authorized: (_req: NextApiRequest, _res: NextApiResponse) => Promise<boolean>;
10
11
  }
11
12
  export interface DOSOptions {
package/dist/handlers.js CHANGED
@@ -40,6 +40,15 @@ var mediaHandlerConfig = {
40
40
  var createMediaHandler = (config, options) => {
41
41
  const client = new import_client_s3.S3Client(config.config);
42
42
  const bucket = config.bucket;
43
+ let mediaRoot = config.mediaRoot || "";
44
+ if (mediaRoot) {
45
+ if (!mediaRoot.endsWith("/")) {
46
+ mediaRoot = mediaRoot + "/";
47
+ }
48
+ if (mediaRoot.startsWith("/")) {
49
+ mediaRoot = mediaRoot.substr(1);
50
+ }
51
+ }
43
52
  let cdnUrl = (options == null ? void 0 : options.cdnUrl) || config.config.endpoint.toString().replace(/http(s|):\/\//i, `https://${bucket}.`);
44
53
  cdnUrl = cdnUrl + (cdnUrl.endsWith("/") ? "" : "/");
45
54
  return async (req, res) => {
@@ -50,9 +59,9 @@ var createMediaHandler = (config, options) => {
50
59
  }
51
60
  switch (req.method) {
52
61
  case "GET":
53
- return listMedia(req, res, client, bucket, cdnUrl);
62
+ return listMedia(req, res, client, bucket, mediaRoot, cdnUrl);
54
63
  case "POST":
55
- return uploadMedia(req, res, client, bucket, cdnUrl);
64
+ return uploadMedia(req, res, client, bucket, mediaRoot, cdnUrl);
56
65
  case "DELETE":
57
66
  return deleteAsset(req, res, client, bucket);
58
67
  default:
@@ -60,7 +69,7 @@ var createMediaHandler = (config, options) => {
60
69
  }
61
70
  };
62
71
  };
63
- async function uploadMedia(req, res, client, bucket, cdnUrl) {
72
+ async function uploadMedia(req, res, client, bucket, mediaRoot, cdnUrl) {
64
73
  const upload = (0, import_util.promisify)((0, import_multer.default)({
65
74
  storage: import_multer.default.diskStorage({
66
75
  directory: (req2, file, cb) => {
@@ -81,26 +90,43 @@ async function uploadMedia(req, res, client, bucket, cdnUrl) {
81
90
  const filename = import_path.default.basename(filePath);
82
91
  const params = {
83
92
  Bucket: bucket,
84
- Key: prefix + filename,
93
+ Key: mediaRoot ? import_path.default.join(mediaRoot, prefix + filename) : prefix + filename,
85
94
  Body: blob,
86
95
  ACL: "public-read"
87
96
  };
88
97
  const command = new import_client_s3.PutObjectCommand(params);
89
98
  try {
99
+ const src = cdnUrl + prefix + filename;
90
100
  await client.send(command);
91
101
  res.json({
92
102
  type: "file",
93
103
  id: prefix + filename,
94
104
  filename,
95
105
  directory: prefix,
96
- previewSrc: cdnUrl + prefix + filename,
97
- src: cdnUrl + prefix + filename
106
+ thumbnail: src,
107
+ src: cdnUrl + (mediaRoot ? import_path.default.join(mediaRoot, prefix + filename) : prefix + filename)
98
108
  });
99
109
  } catch (e) {
100
110
  res.status(500).send(findErrorMessage(e));
101
111
  }
102
112
  }
103
- async function listMedia(req, res, client, bucket, cdnUrl) {
113
+ function stripMediaRoot(mediaRoot, key) {
114
+ if (!mediaRoot) {
115
+ return key;
116
+ }
117
+ const mediaRootParts = mediaRoot.split("/").filter((part) => part);
118
+ if (!mediaRootParts || !mediaRootParts[0]) {
119
+ return key;
120
+ }
121
+ const keyParts = key.split("/").filter((part) => part);
122
+ for (let i = 0; i < mediaRootParts.length; i++) {
123
+ if (keyParts[0] === mediaRootParts[i]) {
124
+ keyParts.shift();
125
+ }
126
+ }
127
+ return keyParts.join("/");
128
+ }
129
+ async function listMedia(req, res, client, bucket, mediaRoot, cdnUrl) {
104
130
  var _a;
105
131
  try {
106
132
  const {
@@ -114,20 +140,28 @@ async function listMedia(req, res, client, bucket, cdnUrl) {
114
140
  const params = {
115
141
  Bucket: bucket,
116
142
  Delimiter: "/",
117
- Prefix: prefix,
143
+ Prefix: mediaRoot ? import_path.default.join(mediaRoot, prefix) : prefix,
118
144
  Marker: offset == null ? void 0 : offset.toString(),
119
145
  MaxKeys: directory && !offset ? +limit + 1 : +limit
120
146
  };
121
- const command = new import_client_s3.ListObjectsCommand(params);
122
- const response = await client.send(command);
147
+ const response = await client.send(new import_client_s3.ListObjectsCommand(params));
123
148
  const items = [];
124
- (_a = response.CommonPrefixes) == null ? void 0 : _a.forEach(({ Prefix }) => items.push({
125
- id: Prefix,
126
- type: "dir",
127
- filename: import_path.default.basename(Prefix),
128
- directory: import_path.default.dirname(Prefix)
129
- }));
130
- items.push(...(response.Contents || []).filter((file) => file.Key !== prefix).map(getDOSToTinaFunc(cdnUrl)));
149
+ (_a = response.CommonPrefixes) == null ? void 0 : _a.forEach(({ Prefix }) => {
150
+ const strippedPrefix = stripMediaRoot(mediaRoot, Prefix);
151
+ if (!strippedPrefix) {
152
+ return;
153
+ }
154
+ items.push({
155
+ id: Prefix,
156
+ type: "dir",
157
+ filename: import_path.default.basename(strippedPrefix),
158
+ directory: import_path.default.dirname(strippedPrefix)
159
+ });
160
+ });
161
+ items.push(...(response.Contents || []).filter((file) => {
162
+ const strippedKey = stripMediaRoot(mediaRoot, file.Key);
163
+ return strippedKey !== prefix;
164
+ }).map(getDOSToTinaFunc(cdnUrl, mediaRoot)));
131
165
  res.json({
132
166
  items,
133
167
  offset: response.NextMarker
@@ -154,9 +188,8 @@ async function deleteAsset(req, res, client, bucket) {
154
188
  Bucket: bucket,
155
189
  Key: objectKey
156
190
  };
157
- const command = new import_client_s3.DeleteObjectCommand(params);
158
191
  try {
159
- const data = await client.send(command);
192
+ const data = await client.send(new import_client_s3.DeleteObjectCommand(params));
160
193
  res.json(data);
161
194
  } catch (err) {
162
195
  res.status(500).json({
@@ -164,16 +197,18 @@ async function deleteAsset(req, res, client, bucket) {
164
197
  });
165
198
  }
166
199
  }
167
- function getDOSToTinaFunc(cdnUrl) {
200
+ function getDOSToTinaFunc(cdnUrl, mediaRoot) {
168
201
  return function dosToTina(file) {
169
- const filename = import_path.default.basename(file.Key);
170
- const directory = import_path.default.dirname(file.Key) + "/";
202
+ const strippedKey = stripMediaRoot(mediaRoot, file.Key);
203
+ const filename = import_path.default.basename(strippedKey);
204
+ const directory = import_path.default.dirname(strippedKey) + "/";
205
+ const src = cdnUrl + file.Key;
171
206
  return {
172
207
  id: file.Key,
173
208
  filename,
174
209
  directory,
175
- src: cdnUrl + file.Key,
176
- previewSrc: cdnUrl + file.Key,
210
+ src,
211
+ thumbnail: src,
177
212
  type: "file"
178
213
  };
179
214
  };