next-tinacms-cloudinary 0.0.0-fbcd928-20241024223724 → 0.0.0-fd7d6a8-20251202025028
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 +1 -1
- package/dist/handlers.js +28 -63
- package/dist/index.js +138 -141
- package/package.json +7 -7
- package/dist/index.mjs +0 -146
package/README.md
CHANGED
|
@@ -92,7 +92,7 @@ Call `createMediaHandler` to set up routes and connect your instance of the Medi
|
|
|
92
92
|
|
|
93
93
|
Import `isAuthorized` from [`@tinacms/auth`](https://github.com/tinacms/tinacms/tree/main/packages/%40tinacms/auth).
|
|
94
94
|
|
|
95
|
-
The `authorized` key will make it so only authorized users within
|
|
95
|
+
The `authorized` key will make it so only authorized users within TinaCloud can upload and make media edits.
|
|
96
96
|
|
|
97
97
|
|
|
98
98
|
```
|
package/dist/handlers.js
CHANGED
|
@@ -1,45 +1,15 @@
|
|
|
1
|
-
var __create = Object.create;
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
var __export = (target, all) => {
|
|
8
|
-
for (var name in all)
|
|
9
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
-
};
|
|
11
|
-
var __copyProps = (to, from, except, desc) => {
|
|
12
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
-
for (let key of __getOwnPropNames(from))
|
|
14
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
-
}
|
|
17
|
-
return to;
|
|
18
|
-
};
|
|
19
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
21
|
-
mod
|
|
22
|
-
));
|
|
23
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
24
|
-
|
|
25
1
|
// src/handlers.ts
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
});
|
|
31
|
-
module.exports = __toCommonJS(handlers_exports);
|
|
32
|
-
var import_cloudinary = require("cloudinary");
|
|
33
|
-
var import_path = __toESM(require("path"));
|
|
34
|
-
var import_multer = __toESM(require("multer"));
|
|
35
|
-
var import_util = require("util");
|
|
2
|
+
import { v2 as cloudinary } from "cloudinary";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import multer from "multer";
|
|
5
|
+
import { promisify } from "util";
|
|
36
6
|
var mediaHandlerConfig = {
|
|
37
7
|
api: {
|
|
38
8
|
bodyParser: false
|
|
39
9
|
}
|
|
40
10
|
};
|
|
41
11
|
var createMediaHandler = (config, options) => {
|
|
42
|
-
|
|
12
|
+
cloudinary.config(Object.assign({ secure: true }, config));
|
|
43
13
|
return async (req, res) => {
|
|
44
14
|
const isAuthorized = await config.authorized(req, res);
|
|
45
15
|
if (!isAuthorized) {
|
|
@@ -59,9 +29,10 @@ var createMediaHandler = (config, options) => {
|
|
|
59
29
|
};
|
|
60
30
|
};
|
|
61
31
|
async function uploadMedia(req, res) {
|
|
62
|
-
const upload =
|
|
63
|
-
(
|
|
64
|
-
storage:
|
|
32
|
+
const upload = promisify(
|
|
33
|
+
multer({
|
|
34
|
+
storage: multer.diskStorage({
|
|
35
|
+
// @ts-ignore
|
|
65
36
|
directory: (req2, file, cb) => {
|
|
66
37
|
cb(null, "/tmp");
|
|
67
38
|
},
|
|
@@ -74,7 +45,7 @@ async function uploadMedia(req, res) {
|
|
|
74
45
|
await upload(req, res);
|
|
75
46
|
const { directory } = req.body;
|
|
76
47
|
try {
|
|
77
|
-
const result = await
|
|
48
|
+
const result = await cloudinary.uploader.upload(req.file.path, {
|
|
78
49
|
folder: directory.replace(/^\//, ""),
|
|
79
50
|
use_filename: true,
|
|
80
51
|
overwrite: false,
|
|
@@ -86,7 +57,6 @@ async function uploadMedia(req, res) {
|
|
|
86
57
|
}
|
|
87
58
|
}
|
|
88
59
|
async function listMedia(req, res, opts) {
|
|
89
|
-
var _a;
|
|
90
60
|
try {
|
|
91
61
|
const mediaListOptions = {
|
|
92
62
|
directory: req.query.directory || '""',
|
|
@@ -96,13 +66,13 @@ async function listMedia(req, res, opts) {
|
|
|
96
66
|
};
|
|
97
67
|
const useRootDirectory = !mediaListOptions.directory || mediaListOptions.directory === "/" || mediaListOptions.directory === '""';
|
|
98
68
|
const query = useRootDirectory ? 'folder=""' : `folder="${mediaListOptions.directory}"`;
|
|
99
|
-
const response = await
|
|
69
|
+
const response = await cloudinary.search.expression(query).max_results(mediaListOptions.limit).next_cursor(mediaListOptions.offset).execute();
|
|
100
70
|
const files = response.resources.map(getCloudinaryToTinaFunc(opts));
|
|
101
|
-
|
|
71
|
+
cloudinary.api.folders = (directory = '""') => {
|
|
102
72
|
if (useRootDirectory) {
|
|
103
|
-
return
|
|
73
|
+
return cloudinary.api.root_folders();
|
|
104
74
|
} else {
|
|
105
|
-
return
|
|
75
|
+
return cloudinary.api.sub_folders(directory);
|
|
106
76
|
}
|
|
107
77
|
};
|
|
108
78
|
let folders = [];
|
|
@@ -115,23 +85,23 @@ async function listMedia(req, res, opts) {
|
|
|
115
85
|
return;
|
|
116
86
|
}
|
|
117
87
|
try {
|
|
118
|
-
folderRes = await
|
|
88
|
+
folderRes = await cloudinary.api.folders(mediaListOptions.directory);
|
|
119
89
|
} catch (e) {
|
|
120
|
-
if (
|
|
90
|
+
if (e.error?.message.startsWith("Can't find folder with path")) {
|
|
121
91
|
} else {
|
|
122
92
|
console.error("Error getting folders");
|
|
123
93
|
console.error(e);
|
|
124
94
|
throw e;
|
|
125
95
|
}
|
|
126
96
|
}
|
|
127
|
-
if (folderRes
|
|
97
|
+
if (folderRes?.folders) {
|
|
128
98
|
folders = folderRes.folders.map(function(folder) {
|
|
129
99
|
"empty-repo/004";
|
|
130
100
|
return {
|
|
131
101
|
id: folder.path,
|
|
132
102
|
type: "dir",
|
|
133
|
-
filename:
|
|
134
|
-
directory:
|
|
103
|
+
filename: path.basename(folder.path),
|
|
104
|
+
directory: path.dirname(folder.path)
|
|
135
105
|
};
|
|
136
106
|
});
|
|
137
107
|
}
|
|
@@ -147,20 +117,16 @@ async function listMedia(req, res, opts) {
|
|
|
147
117
|
}
|
|
148
118
|
}
|
|
149
119
|
var findErrorMessage = (e) => {
|
|
150
|
-
if (typeof e == "string")
|
|
151
|
-
|
|
152
|
-
if (e.message)
|
|
153
|
-
return e.message;
|
|
154
|
-
if (e.error && e.error.message)
|
|
155
|
-
return e.error.message;
|
|
120
|
+
if (typeof e == "string") return e;
|
|
121
|
+
if (e.message) return e.message;
|
|
122
|
+
if (e.error && e.error.message) return e.error.message;
|
|
156
123
|
return "an error occurred";
|
|
157
124
|
};
|
|
158
125
|
async function deleteAsset(req, res) {
|
|
159
126
|
const { media } = req.query;
|
|
160
127
|
const [, public_id] = media;
|
|
161
|
-
|
|
162
|
-
if (err)
|
|
163
|
-
res.status(500);
|
|
128
|
+
cloudinary.uploader.destroy(public_id, {}, (err) => {
|
|
129
|
+
if (err) res.status(500);
|
|
164
130
|
res.json({
|
|
165
131
|
err,
|
|
166
132
|
public_id
|
|
@@ -174,8 +140,8 @@ function getCloudinaryToTinaFunc(opts) {
|
|
|
174
140
|
useHttps = opts.useHttps;
|
|
175
141
|
}
|
|
176
142
|
const sel = useHttps ? "secure_url" : "url";
|
|
177
|
-
const filename =
|
|
178
|
-
const directory =
|
|
143
|
+
const filename = path.basename(file.public_id);
|
|
144
|
+
const directory = path.dirname(file.public_id);
|
|
179
145
|
return {
|
|
180
146
|
id: file.public_id,
|
|
181
147
|
filename,
|
|
@@ -203,8 +169,7 @@ function transformCloudinaryImage(url, transformations) {
|
|
|
203
169
|
}
|
|
204
170
|
return url;
|
|
205
171
|
}
|
|
206
|
-
|
|
207
|
-
0 && (module.exports = {
|
|
172
|
+
export {
|
|
208
173
|
createMediaHandler,
|
|
209
174
|
mediaHandlerConfig
|
|
210
|
-
}
|
|
175
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -1,149 +1,146 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
this.ERR_TYPE = "MediaListError";
|
|
9
|
-
this.title = config.title;
|
|
10
|
-
this.docsLink = config.docsLink;
|
|
11
|
-
}
|
|
1
|
+
import { DEFAULT_MEDIA_UPLOAD_TYPES } from "tinacms";
|
|
2
|
+
class MediaListError extends Error {
|
|
3
|
+
constructor(config) {
|
|
4
|
+
super(config.message);
|
|
5
|
+
this.ERR_TYPE = "MediaListError";
|
|
6
|
+
this.title = config.title;
|
|
7
|
+
this.docsLink = config.docsLink;
|
|
12
8
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
9
|
+
}
|
|
10
|
+
const E_DEFAULT = new MediaListError({
|
|
11
|
+
title: "An Error Occurred",
|
|
12
|
+
message: "Something went wrong fetching your media from Cloudinary.",
|
|
13
|
+
docsLink: "https://tina.io/docs/r/cloudinary"
|
|
14
|
+
});
|
|
15
|
+
const E_UNAUTHORIZED = new MediaListError({
|
|
16
|
+
title: "Unauthorized",
|
|
17
|
+
message: "You don't have access to this resource.",
|
|
18
|
+
docsLink: "https://tina.io/docs/r/cloudinary"
|
|
19
|
+
});
|
|
20
|
+
const E_CONFIG = new MediaListError({
|
|
21
|
+
title: "Missing Credentials",
|
|
22
|
+
message: "Unable to connect to Cloudinary because one or more environment variables are missing.",
|
|
23
|
+
docsLink: "https://tina.io/docs/r/cloudinary/"
|
|
24
|
+
});
|
|
25
|
+
const E_KEY_FAIL = new MediaListError({
|
|
26
|
+
title: "Bad Credentials",
|
|
27
|
+
message: "Unable to connect to Cloudinary because one or more environment variables are misconfigured.",
|
|
28
|
+
docsLink: "https://tina.io/docs/r/cloudinary/"
|
|
29
|
+
});
|
|
30
|
+
const E_BAD_ROUTE = new MediaListError({
|
|
31
|
+
title: "Bad Route",
|
|
32
|
+
message: "The Cloudinary API route is missing or misconfigured.",
|
|
33
|
+
docsLink: "https://tina.io/docs/r/cloudinary"
|
|
34
|
+
});
|
|
35
|
+
const interpretErrorMessage = (message) => {
|
|
36
|
+
switch (message) {
|
|
37
|
+
case "Must supply cloud_name":
|
|
38
|
+
case "Must supply api_key":
|
|
39
|
+
case "Must supply api_secret":
|
|
40
|
+
return E_CONFIG;
|
|
41
|
+
case "unknown api_key":
|
|
42
|
+
return E_KEY_FAIL;
|
|
43
|
+
default:
|
|
44
|
+
return E_DEFAULT;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
class CloudinaryMediaStore {
|
|
48
|
+
constructor(options) {
|
|
49
|
+
this.fetchFunction = (input, init) => fetch(input, init);
|
|
50
|
+
this.accept = DEFAULT_MEDIA_UPLOAD_TYPES;
|
|
51
|
+
this.parse = (img) => {
|
|
52
|
+
return img.src;
|
|
53
|
+
};
|
|
54
|
+
this.baseUrl = (options == null ? void 0 : options.baseUrl) || "/api/cloudinary/media";
|
|
55
|
+
}
|
|
56
|
+
async persist(media) {
|
|
57
|
+
const newFiles = [];
|
|
58
|
+
for (const item of media) {
|
|
59
|
+
const { file, directory } = item;
|
|
60
|
+
const formData = new FormData();
|
|
61
|
+
formData.append("file", file);
|
|
62
|
+
formData.append("directory", directory);
|
|
63
|
+
formData.append("filename", file.name);
|
|
64
|
+
const res = await this.fetchFunction(this.baseUrl, {
|
|
65
|
+
method: "POST",
|
|
66
|
+
body: formData
|
|
67
|
+
});
|
|
68
|
+
if (res.status != 200) {
|
|
69
|
+
const responseData = await res.json();
|
|
70
|
+
throw new Error(responseData.message);
|
|
71
|
+
}
|
|
72
|
+
const fileRes = await res.json();
|
|
73
|
+
await new Promise((resolve) => {
|
|
74
|
+
setTimeout(resolve, 2e3);
|
|
75
|
+
});
|
|
76
|
+
const parsedRes = {
|
|
77
|
+
type: "file",
|
|
78
|
+
id: fileRes.public_id,
|
|
79
|
+
filename: fileRes.original_filename,
|
|
80
|
+
directory: "/",
|
|
81
|
+
thumbnails: {
|
|
82
|
+
"75x75": fileRes.secure_url,
|
|
83
|
+
"400x400": fileRes.secure_url,
|
|
84
|
+
"1000x1000": fileRes.secure_url
|
|
85
|
+
},
|
|
86
|
+
src: fileRes.secure_url
|
|
56
87
|
};
|
|
57
|
-
|
|
88
|
+
newFiles.push(parsedRes);
|
|
58
89
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
formData.append("filename", file.name);
|
|
67
|
-
const res = await this.fetchFunction(this.baseUrl, {
|
|
68
|
-
method: "POST",
|
|
69
|
-
body: formData
|
|
70
|
-
});
|
|
71
|
-
if (res.status != 200) {
|
|
72
|
-
const responseData = await res.json();
|
|
73
|
-
throw new Error(responseData.message);
|
|
74
|
-
}
|
|
75
|
-
const fileRes = await res.json();
|
|
76
|
-
await new Promise((resolve) => {
|
|
77
|
-
setTimeout(resolve, 2e3);
|
|
78
|
-
});
|
|
79
|
-
const parsedRes = {
|
|
80
|
-
type: "file",
|
|
81
|
-
id: fileRes.public_id,
|
|
82
|
-
filename: fileRes.original_filename,
|
|
83
|
-
directory: "/",
|
|
84
|
-
thumbnails: {
|
|
85
|
-
"75x75": fileRes.secure_url,
|
|
86
|
-
"400x400": fileRes.secure_url,
|
|
87
|
-
"1000x1000": fileRes.secure_url
|
|
88
|
-
},
|
|
89
|
-
src: fileRes.secure_url
|
|
90
|
-
};
|
|
91
|
-
newFiles.push(parsedRes);
|
|
90
|
+
return newFiles;
|
|
91
|
+
}
|
|
92
|
+
async delete(media) {
|
|
93
|
+
await this.fetchFunction(
|
|
94
|
+
`${this.baseUrl}/${encodeURIComponent(media.id)}`,
|
|
95
|
+
{
|
|
96
|
+
method: "DELETE"
|
|
92
97
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}
|
|
101
|
-
);
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
async list(options) {
|
|
101
|
+
const query = this.buildQuery(options);
|
|
102
|
+
const response = await this.fetchFunction(this.baseUrl + query);
|
|
103
|
+
if (response.status == 401) {
|
|
104
|
+
throw E_UNAUTHORIZED;
|
|
102
105
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
const response = await this.fetchFunction(this.baseUrl + query);
|
|
106
|
-
if (response.status == 401) {
|
|
107
|
-
throw E_UNAUTHORIZED;
|
|
108
|
-
}
|
|
109
|
-
if (response.status == 404) {
|
|
110
|
-
throw E_BAD_ROUTE;
|
|
111
|
-
}
|
|
112
|
-
if (response.status >= 500) {
|
|
113
|
-
const { e } = await response.json();
|
|
114
|
-
const error = interpretErrorMessage(e);
|
|
115
|
-
throw error;
|
|
116
|
-
}
|
|
117
|
-
const { items, offset } = await response.json();
|
|
118
|
-
return {
|
|
119
|
-
items: items.map((item) => item),
|
|
120
|
-
nextOffset: offset
|
|
121
|
-
};
|
|
106
|
+
if (response.status == 404) {
|
|
107
|
+
throw E_BAD_ROUTE;
|
|
122
108
|
}
|
|
123
|
-
|
|
124
|
-
const
|
|
125
|
-
|
|
109
|
+
if (response.status >= 500) {
|
|
110
|
+
const { e } = await response.json();
|
|
111
|
+
const error = interpretErrorMessage(e);
|
|
112
|
+
throw error;
|
|
126
113
|
}
|
|
114
|
+
const { items, offset } = await response.json();
|
|
115
|
+
return {
|
|
116
|
+
items: items.map((item) => item),
|
|
117
|
+
nextOffset: offset
|
|
118
|
+
};
|
|
127
119
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
120
|
+
buildQuery(options) {
|
|
121
|
+
const params = Object.keys(options).filter((key) => options[key] !== "" && options[key] !== void 0).map((key) => `${key}=${options[key]}`).join("&");
|
|
122
|
+
return `?${params}`;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
const createTinaCloudCloudinaryMediaStore = (options = { baseUrl: "/api/cloudinary/media" }) => class TinaCloudCloudinaryMediaStore extends CloudinaryMediaStore {
|
|
126
|
+
constructor(client) {
|
|
127
|
+
super(options);
|
|
128
|
+
this.client = client;
|
|
129
|
+
this.fetchFunction = async (input, init) => {
|
|
130
|
+
try {
|
|
131
|
+
const url = input.toString();
|
|
132
|
+
const query = `${url.includes("?") ? "&" : "?"}clientID=${client.clientId}`;
|
|
133
|
+
const res = client.authProvider.fetchWithToken(url + query, init);
|
|
134
|
+
return res;
|
|
135
|
+
} catch (error) {
|
|
136
|
+
console.error(error);
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
const TinaCloudCloudinaryMediaStore = createTinaCloudCloudinaryMediaStore();
|
|
142
|
+
export {
|
|
143
|
+
CloudinaryMediaStore,
|
|
144
|
+
TinaCloudCloudinaryMediaStore,
|
|
145
|
+
createTinaCloudCloudinaryMediaStore
|
|
146
|
+
};
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "next-tinacms-cloudinary",
|
|
3
|
-
"version": "0.0.0-
|
|
3
|
+
"version": "0.0.0-fd7d6a8-20251202025028",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
|
-
"module": "dist/index.
|
|
5
|
+
"module": "./dist/index.js",
|
|
6
6
|
"files": [
|
|
7
7
|
"dist"
|
|
8
8
|
],
|
|
@@ -24,16 +24,16 @@
|
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@types/crypto-js": "^3.1.47",
|
|
26
26
|
"@types/js-cookie": "^2.2.7",
|
|
27
|
-
"@types/node": "^22.
|
|
27
|
+
"@types/node": "^22.13.1",
|
|
28
28
|
"next": "14.2.10",
|
|
29
29
|
"react": "^18.3.1",
|
|
30
30
|
"react-dom": "^18.3.1",
|
|
31
|
-
"typescript": "^5.
|
|
32
|
-
"@tinacms/scripts": "1.
|
|
33
|
-
"tinacms": "0.0.0-
|
|
31
|
+
"typescript": "^5.7.3",
|
|
32
|
+
"@tinacms/scripts": "1.4.1",
|
|
33
|
+
"tinacms": "0.0.0-fd7d6a8-20251202025028"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
|
36
|
-
"tinacms": "0.0.0-
|
|
36
|
+
"tinacms": "0.0.0-fd7d6a8-20251202025028"
|
|
37
37
|
},
|
|
38
38
|
"publishConfig": {
|
|
39
39
|
"registry": "https://registry.npmjs.org"
|
package/dist/index.mjs
DELETED
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
import { DEFAULT_MEDIA_UPLOAD_TYPES } from "tinacms";
|
|
2
|
-
class MediaListError extends Error {
|
|
3
|
-
constructor(config) {
|
|
4
|
-
super(config.message);
|
|
5
|
-
this.ERR_TYPE = "MediaListError";
|
|
6
|
-
this.title = config.title;
|
|
7
|
-
this.docsLink = config.docsLink;
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
const E_DEFAULT = new MediaListError({
|
|
11
|
-
title: "An Error Occurred",
|
|
12
|
-
message: "Something went wrong fetching your media from Cloudinary.",
|
|
13
|
-
docsLink: "https://tina.io/docs/reference/media/external/cloudinary"
|
|
14
|
-
});
|
|
15
|
-
const E_UNAUTHORIZED = new MediaListError({
|
|
16
|
-
title: "Unauthorized",
|
|
17
|
-
message: "You don't have access to this resource.",
|
|
18
|
-
docsLink: "https://tina.io/docs/reference/media/external/cloudinary/#set-up-api-routes-nextjs-example"
|
|
19
|
-
});
|
|
20
|
-
const E_CONFIG = new MediaListError({
|
|
21
|
-
title: "Missing Credentials",
|
|
22
|
-
message: "Unable to connect to Cloudinary because one or more environment variables are missing.",
|
|
23
|
-
docsLink: "https://tina.io/docs/media-cloudinary/"
|
|
24
|
-
});
|
|
25
|
-
const E_KEY_FAIL = new MediaListError({
|
|
26
|
-
title: "Bad Credentials",
|
|
27
|
-
message: "Unable to connect to Cloudinary because one or more environment variables are misconfigured.",
|
|
28
|
-
docsLink: "https://tina.io/docs/media-cloudinary/"
|
|
29
|
-
});
|
|
30
|
-
const E_BAD_ROUTE = new MediaListError({
|
|
31
|
-
title: "Bad Route",
|
|
32
|
-
message: "The Cloudinary API route is missing or misconfigured.",
|
|
33
|
-
docsLink: "https://tina.io/docs/reference/media/external/cloudinary/#set-up-api-routes-nextjs-example"
|
|
34
|
-
});
|
|
35
|
-
const interpretErrorMessage = (message) => {
|
|
36
|
-
switch (message) {
|
|
37
|
-
case "Must supply cloud_name":
|
|
38
|
-
case "Must supply api_key":
|
|
39
|
-
case "Must supply api_secret":
|
|
40
|
-
return E_CONFIG;
|
|
41
|
-
case "unknown api_key":
|
|
42
|
-
return E_KEY_FAIL;
|
|
43
|
-
default:
|
|
44
|
-
return E_DEFAULT;
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
class CloudinaryMediaStore {
|
|
48
|
-
constructor(options) {
|
|
49
|
-
this.fetchFunction = (input, init) => fetch(input, init);
|
|
50
|
-
this.accept = DEFAULT_MEDIA_UPLOAD_TYPES;
|
|
51
|
-
this.parse = (img) => {
|
|
52
|
-
return img.src;
|
|
53
|
-
};
|
|
54
|
-
this.baseUrl = (options == null ? void 0 : options.baseUrl) || "/api/cloudinary/media";
|
|
55
|
-
}
|
|
56
|
-
async persist(media) {
|
|
57
|
-
const newFiles = [];
|
|
58
|
-
for (const item of media) {
|
|
59
|
-
const { file, directory } = item;
|
|
60
|
-
const formData = new FormData();
|
|
61
|
-
formData.append("file", file);
|
|
62
|
-
formData.append("directory", directory);
|
|
63
|
-
formData.append("filename", file.name);
|
|
64
|
-
const res = await this.fetchFunction(this.baseUrl, {
|
|
65
|
-
method: "POST",
|
|
66
|
-
body: formData
|
|
67
|
-
});
|
|
68
|
-
if (res.status != 200) {
|
|
69
|
-
const responseData = await res.json();
|
|
70
|
-
throw new Error(responseData.message);
|
|
71
|
-
}
|
|
72
|
-
const fileRes = await res.json();
|
|
73
|
-
await new Promise((resolve) => {
|
|
74
|
-
setTimeout(resolve, 2e3);
|
|
75
|
-
});
|
|
76
|
-
const parsedRes = {
|
|
77
|
-
type: "file",
|
|
78
|
-
id: fileRes.public_id,
|
|
79
|
-
filename: fileRes.original_filename,
|
|
80
|
-
directory: "/",
|
|
81
|
-
thumbnails: {
|
|
82
|
-
"75x75": fileRes.secure_url,
|
|
83
|
-
"400x400": fileRes.secure_url,
|
|
84
|
-
"1000x1000": fileRes.secure_url
|
|
85
|
-
},
|
|
86
|
-
src: fileRes.secure_url
|
|
87
|
-
};
|
|
88
|
-
newFiles.push(parsedRes);
|
|
89
|
-
}
|
|
90
|
-
return newFiles;
|
|
91
|
-
}
|
|
92
|
-
async delete(media) {
|
|
93
|
-
await this.fetchFunction(
|
|
94
|
-
`${this.baseUrl}/${encodeURIComponent(media.id)}`,
|
|
95
|
-
{
|
|
96
|
-
method: "DELETE"
|
|
97
|
-
}
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
async list(options) {
|
|
101
|
-
const query = this.buildQuery(options);
|
|
102
|
-
const response = await this.fetchFunction(this.baseUrl + query);
|
|
103
|
-
if (response.status == 401) {
|
|
104
|
-
throw E_UNAUTHORIZED;
|
|
105
|
-
}
|
|
106
|
-
if (response.status == 404) {
|
|
107
|
-
throw E_BAD_ROUTE;
|
|
108
|
-
}
|
|
109
|
-
if (response.status >= 500) {
|
|
110
|
-
const { e } = await response.json();
|
|
111
|
-
const error = interpretErrorMessage(e);
|
|
112
|
-
throw error;
|
|
113
|
-
}
|
|
114
|
-
const { items, offset } = await response.json();
|
|
115
|
-
return {
|
|
116
|
-
items: items.map((item) => item),
|
|
117
|
-
nextOffset: offset
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
buildQuery(options) {
|
|
121
|
-
const params = Object.keys(options).filter((key) => options[key] !== "" && options[key] !== void 0).map((key) => `${key}=${options[key]}`).join("&");
|
|
122
|
-
return `?${params}`;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
const createTinaCloudCloudinaryMediaStore = (options = { baseUrl: "/api/cloudinary/media" }) => class TinaCloudCloudinaryMediaStore extends CloudinaryMediaStore {
|
|
126
|
-
constructor(client) {
|
|
127
|
-
super(options);
|
|
128
|
-
this.client = client;
|
|
129
|
-
this.fetchFunction = async (input, init) => {
|
|
130
|
-
try {
|
|
131
|
-
const url = input.toString();
|
|
132
|
-
const query = `${url.includes("?") ? "&" : "?"}clientID=${client.clientId}`;
|
|
133
|
-
const res = client.authProvider.fetchWithToken(url + query, init);
|
|
134
|
-
return res;
|
|
135
|
-
} catch (error) {
|
|
136
|
-
console.error(error);
|
|
137
|
-
}
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
};
|
|
141
|
-
const TinaCloudCloudinaryMediaStore = createTinaCloudCloudinaryMediaStore();
|
|
142
|
-
export {
|
|
143
|
-
CloudinaryMediaStore,
|
|
144
|
-
TinaCloudCloudinaryMediaStore,
|
|
145
|
-
createTinaCloudCloudinaryMediaStore
|
|
146
|
-
};
|