@constructive-io/graphql-explorer 3.1.0 → 4.0.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/esm/server.js +28 -30
- package/esm/settings.js +14 -6
- package/package.json +12 -16
- package/server.d.ts +2 -2
- package/server.js +25 -27
- package/settings.d.ts +7 -2
- package/settings.js +15 -7
- package/esm/resolvers/uploads.js +0 -54
- package/resolvers/uploads.d.ts +0 -31
- package/resolvers/uploads.js +0 -61
package/esm/server.js
CHANGED
|
@@ -2,49 +2,47 @@ import { getEnvOptions } from '@constructive-io/graphql-env';
|
|
|
2
2
|
import { cors, healthz, poweredBy } from '@pgpmjs/server-utils';
|
|
3
3
|
import { middleware as parseDomains } from '@constructive-io/url-domains';
|
|
4
4
|
import express from 'express';
|
|
5
|
-
import { graphileCache } from 'graphile-cache';
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
import { getPgPool } from 'pg-cache';
|
|
5
|
+
import { createGraphileInstance, graphileCache } from 'graphile-cache';
|
|
6
|
+
import { makePgService } from 'graphile-settings';
|
|
7
|
+
import { buildConnectionString, getPgPool } from 'pg-cache';
|
|
9
8
|
import { getPgEnvOptions } from 'pg-env';
|
|
10
|
-
import { postgraphile } from 'postgraphile';
|
|
11
9
|
import { printDatabases, printSchemas } from './render';
|
|
12
|
-
import {
|
|
10
|
+
import { getGraphilePreset } from './settings';
|
|
13
11
|
export const GraphQLExplorer = (rawOpts = {}) => {
|
|
14
12
|
const opts = getEnvOptions(rawOpts);
|
|
15
13
|
const { pg, server } = opts;
|
|
16
|
-
const getGraphileInstanceObj = (dbname, schemaname) => {
|
|
14
|
+
const getGraphileInstanceObj = async (dbname, schemaname) => {
|
|
17
15
|
const key = `${dbname}.${schemaname}`;
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
const cached = graphileCache.get(key);
|
|
17
|
+
if (cached) {
|
|
18
|
+
return cached;
|
|
20
19
|
}
|
|
21
|
-
const
|
|
22
|
-
...
|
|
23
|
-
...opts,
|
|
24
|
-
graphile: { schema: schemaname },
|
|
25
|
-
}),
|
|
26
|
-
graphqlRoute: '/graphql',
|
|
27
|
-
graphiqlRoute: '/graphiql',
|
|
28
|
-
};
|
|
29
|
-
const pgPool = getPgPool(getPgEnvOptions({
|
|
30
|
-
...opts.pg,
|
|
20
|
+
const pgConfig = getPgEnvOptions({
|
|
21
|
+
...pg,
|
|
31
22
|
database: dbname,
|
|
32
|
-
})
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
23
|
+
});
|
|
24
|
+
const connectionString = buildConnectionString(pgConfig.user, pgConfig.password, pgConfig.host, pgConfig.port, pgConfig.database);
|
|
25
|
+
const basePreset = getGraphilePreset(opts);
|
|
26
|
+
const preset = {
|
|
27
|
+
...basePreset,
|
|
28
|
+
pgServices: [
|
|
29
|
+
makePgService({ connectionString, schemas: [schemaname] }),
|
|
30
|
+
],
|
|
31
|
+
grafserv: {
|
|
32
|
+
graphqlPath: '/graphql',
|
|
33
|
+
graphiqlPath: '/graphiql',
|
|
34
|
+
graphiql: true,
|
|
35
|
+
},
|
|
38
36
|
};
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
const instance = await createGraphileInstance({ preset, cacheKey: key });
|
|
38
|
+
graphileCache.set(key, instance);
|
|
39
|
+
return instance;
|
|
41
40
|
};
|
|
42
41
|
const app = express();
|
|
43
42
|
healthz(app);
|
|
44
43
|
cors(app, server.origin);
|
|
45
44
|
app.use(parseDomains());
|
|
46
45
|
app.use(poweredBy('constructive'));
|
|
47
|
-
app.use(graphqlUpload.graphqlUploadExpress());
|
|
48
46
|
app.use(async (req, res, next) => {
|
|
49
47
|
if (req.urlDomains?.subdomains.length === 1) {
|
|
50
48
|
const [dbName] = req.urlDomains.subdomains;
|
|
@@ -105,8 +103,8 @@ export const GraphQLExplorer = (rawOpts = {}) => {
|
|
|
105
103
|
if (req.urlDomains?.subdomains.length === 2) {
|
|
106
104
|
const [schemaName, dbName] = req.urlDomains.subdomains;
|
|
107
105
|
try {
|
|
108
|
-
const
|
|
109
|
-
handler(req, res, next);
|
|
106
|
+
const instance = await getGraphileInstanceObj(dbName, schemaName);
|
|
107
|
+
instance.handler(req, res, next);
|
|
110
108
|
return;
|
|
111
109
|
}
|
|
112
110
|
catch (e) {
|
package/esm/settings.js
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
import { getEnvOptions } from '@constructive-io/graphql-env';
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import { ConstructivePreset } from 'graphile-settings';
|
|
3
|
+
/**
|
|
4
|
+
* Get a GraphileConfig.Preset for the explorer with grafast context configured.
|
|
5
|
+
*
|
|
6
|
+
* This returns a v5 preset that can be extended with pgServices.
|
|
7
|
+
*/
|
|
8
|
+
export const getGraphilePreset = (rawOpts) => {
|
|
4
9
|
const opts = getEnvOptions(rawOpts);
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
10
|
+
return {
|
|
11
|
+
extends: [ConstructivePreset],
|
|
12
|
+
grafast: {
|
|
13
|
+
context: () => ({
|
|
14
|
+
pgSettings: { role: opts.pg?.user ?? 'postgres' },
|
|
15
|
+
}),
|
|
16
|
+
},
|
|
8
17
|
};
|
|
9
|
-
return baseOptions;
|
|
10
18
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@constructive-io/graphql-explorer",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"author": "Constructive <developers@constructive.io>",
|
|
5
5
|
"description": "Constructive GraphQL Explorer",
|
|
6
6
|
"main": "index.js",
|
|
@@ -34,27 +34,23 @@
|
|
|
34
34
|
"test:watch": "jest --watch"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@constructive-io/graphql-env": "^
|
|
38
|
-
"@constructive-io/graphql-types": "^
|
|
39
|
-
"@constructive-io/s3-streamer": "^2.11.0",
|
|
40
|
-
"@constructive-io/upload-names": "^2.5.0",
|
|
37
|
+
"@constructive-io/graphql-env": "^3.0.0",
|
|
38
|
+
"@constructive-io/graphql-types": "^3.0.0",
|
|
41
39
|
"@constructive-io/url-domains": "^2.5.0",
|
|
42
40
|
"@pgpmjs/server-utils": "^3.1.0",
|
|
43
|
-
"@pgpmjs/types": "^2.16.0",
|
|
44
41
|
"express": "^5.2.1",
|
|
45
|
-
"
|
|
46
|
-
"graphile-cache": "^
|
|
47
|
-
"graphile-
|
|
48
|
-
"
|
|
49
|
-
"graphql
|
|
50
|
-
"pg-cache": "^
|
|
42
|
+
"grafserv": "^1.0.0-rc.4",
|
|
43
|
+
"graphile-cache": "^3.0.0",
|
|
44
|
+
"graphile-config": "1.0.0-rc.3",
|
|
45
|
+
"graphile-settings": "^4.0.0",
|
|
46
|
+
"graphql": "^16.9.0",
|
|
47
|
+
"pg-cache": "^3.0.0",
|
|
51
48
|
"pg-env": "^1.4.0",
|
|
52
|
-
"postgraphile": "^
|
|
49
|
+
"postgraphile": "^5.0.0-rc.4"
|
|
53
50
|
},
|
|
54
51
|
"devDependencies": {
|
|
55
52
|
"@types/express": "^5.0.6",
|
|
56
|
-
"
|
|
57
|
-
"makage": "^0.1.12",
|
|
53
|
+
"makage": "^0.1.10",
|
|
58
54
|
"nodemon": "^3.1.10",
|
|
59
55
|
"ts-node": "^10.9.2"
|
|
60
56
|
},
|
|
@@ -65,5 +61,5 @@
|
|
|
65
61
|
"constructive",
|
|
66
62
|
"interface"
|
|
67
63
|
],
|
|
68
|
-
"gitHead": "
|
|
64
|
+
"gitHead": "b2daeefe49cdefb3d01ea63cf778fb9b847ab5fe"
|
|
69
65
|
}
|
package/server.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { ConstructiveOptions } from '@constructive-io/graphql-types';
|
|
2
2
|
import { Express } from 'express';
|
|
3
|
-
export declare const GraphQLExplorer: (rawOpts?:
|
|
3
|
+
export declare const GraphQLExplorer: (rawOpts?: ConstructiveOptions) => Express;
|
package/server.js
CHANGED
|
@@ -9,48 +9,46 @@ const server_utils_1 = require("@pgpmjs/server-utils");
|
|
|
9
9
|
const url_domains_1 = require("@constructive-io/url-domains");
|
|
10
10
|
const express_1 = __importDefault(require("express"));
|
|
11
11
|
const graphile_cache_1 = require("graphile-cache");
|
|
12
|
-
const
|
|
13
|
-
// Scalar
|
|
12
|
+
const graphile_settings_1 = require("graphile-settings");
|
|
14
13
|
const pg_cache_1 = require("pg-cache");
|
|
15
14
|
const pg_env_1 = require("pg-env");
|
|
16
|
-
const postgraphile_1 = require("postgraphile");
|
|
17
15
|
const render_1 = require("./render");
|
|
18
16
|
const settings_1 = require("./settings");
|
|
19
17
|
const GraphQLExplorer = (rawOpts = {}) => {
|
|
20
18
|
const opts = (0, graphql_env_1.getEnvOptions)(rawOpts);
|
|
21
19
|
const { pg, server } = opts;
|
|
22
|
-
const getGraphileInstanceObj = (dbname, schemaname) => {
|
|
20
|
+
const getGraphileInstanceObj = async (dbname, schemaname) => {
|
|
23
21
|
const key = `${dbname}.${schemaname}`;
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
const cached = graphile_cache_1.graphileCache.get(key);
|
|
23
|
+
if (cached) {
|
|
24
|
+
return cached;
|
|
26
25
|
}
|
|
27
|
-
const
|
|
28
|
-
...
|
|
29
|
-
...opts,
|
|
30
|
-
graphile: { schema: schemaname },
|
|
31
|
-
}),
|
|
32
|
-
graphqlRoute: '/graphql',
|
|
33
|
-
graphiqlRoute: '/graphiql',
|
|
34
|
-
};
|
|
35
|
-
const pgPool = (0, pg_cache_1.getPgPool)((0, pg_env_1.getPgEnvOptions)({
|
|
36
|
-
...opts.pg,
|
|
26
|
+
const pgConfig = (0, pg_env_1.getPgEnvOptions)({
|
|
27
|
+
...pg,
|
|
37
28
|
database: dbname,
|
|
38
|
-
})
|
|
39
|
-
const
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
29
|
+
});
|
|
30
|
+
const connectionString = (0, pg_cache_1.buildConnectionString)(pgConfig.user, pgConfig.password, pgConfig.host, pgConfig.port, pgConfig.database);
|
|
31
|
+
const basePreset = (0, settings_1.getGraphilePreset)(opts);
|
|
32
|
+
const preset = {
|
|
33
|
+
...basePreset,
|
|
34
|
+
pgServices: [
|
|
35
|
+
(0, graphile_settings_1.makePgService)({ connectionString, schemas: [schemaname] }),
|
|
36
|
+
],
|
|
37
|
+
grafserv: {
|
|
38
|
+
graphqlPath: '/graphql',
|
|
39
|
+
graphiqlPath: '/graphiql',
|
|
40
|
+
graphiql: true,
|
|
41
|
+
},
|
|
44
42
|
};
|
|
45
|
-
graphile_cache_1.
|
|
46
|
-
|
|
43
|
+
const instance = await (0, graphile_cache_1.createGraphileInstance)({ preset, cacheKey: key });
|
|
44
|
+
graphile_cache_1.graphileCache.set(key, instance);
|
|
45
|
+
return instance;
|
|
47
46
|
};
|
|
48
47
|
const app = (0, express_1.default)();
|
|
49
48
|
(0, server_utils_1.healthz)(app);
|
|
50
49
|
(0, server_utils_1.cors)(app, server.origin);
|
|
51
50
|
app.use((0, url_domains_1.middleware)());
|
|
52
51
|
app.use((0, server_utils_1.poweredBy)('constructive'));
|
|
53
|
-
app.use(graphql_upload_1.default.graphqlUploadExpress());
|
|
54
52
|
app.use(async (req, res, next) => {
|
|
55
53
|
if (req.urlDomains?.subdomains.length === 1) {
|
|
56
54
|
const [dbName] = req.urlDomains.subdomains;
|
|
@@ -111,8 +109,8 @@ const GraphQLExplorer = (rawOpts = {}) => {
|
|
|
111
109
|
if (req.urlDomains?.subdomains.length === 2) {
|
|
112
110
|
const [schemaName, dbName] = req.urlDomains.subdomains;
|
|
113
111
|
try {
|
|
114
|
-
const
|
|
115
|
-
handler(req, res, next);
|
|
112
|
+
const instance = await getGraphileInstanceObj(dbName, schemaName);
|
|
113
|
+
instance.handler(req, res, next);
|
|
116
114
|
return;
|
|
117
115
|
}
|
|
118
116
|
catch (e) {
|
package/settings.d.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
1
|
import { ConstructiveOptions } from '@constructive-io/graphql-types';
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import type { GraphileConfig } from 'graphile-config';
|
|
3
|
+
/**
|
|
4
|
+
* Get a GraphileConfig.Preset for the explorer with grafast context configured.
|
|
5
|
+
*
|
|
6
|
+
* This returns a v5 preset that can be extended with pgServices.
|
|
7
|
+
*/
|
|
8
|
+
export declare const getGraphilePreset: (rawOpts: ConstructiveOptions) => GraphileConfig.Preset;
|
package/settings.js
CHANGED
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.getGraphilePreset = void 0;
|
|
4
4
|
const graphql_env_1 = require("@constructive-io/graphql-env");
|
|
5
5
|
const graphile_settings_1 = require("graphile-settings");
|
|
6
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Get a GraphileConfig.Preset for the explorer with grafast context configured.
|
|
8
|
+
*
|
|
9
|
+
* This returns a v5 preset that can be extended with pgServices.
|
|
10
|
+
*/
|
|
11
|
+
const getGraphilePreset = (rawOpts) => {
|
|
7
12
|
const opts = (0, graphql_env_1.getEnvOptions)(rawOpts);
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
13
|
+
return {
|
|
14
|
+
extends: [graphile_settings_1.ConstructivePreset],
|
|
15
|
+
grafast: {
|
|
16
|
+
context: () => ({
|
|
17
|
+
pgSettings: { role: opts.pg?.user ?? 'postgres' },
|
|
18
|
+
}),
|
|
19
|
+
},
|
|
11
20
|
};
|
|
12
|
-
return baseOptions;
|
|
13
21
|
};
|
|
14
|
-
exports.
|
|
22
|
+
exports.getGraphilePreset = getGraphilePreset;
|
package/esm/resolvers/uploads.js
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import Streamer from '@constructive-io/s3-streamer';
|
|
2
|
-
import uploadNames from '@constructive-io/upload-names';
|
|
3
|
-
export class UploadHandler {
|
|
4
|
-
options;
|
|
5
|
-
streamer;
|
|
6
|
-
constructor(options) {
|
|
7
|
-
this.options = options;
|
|
8
|
-
this.streamer = new Streamer({
|
|
9
|
-
defaultBucket: options.bucketName,
|
|
10
|
-
awsRegion: options.awsRegion,
|
|
11
|
-
awsSecretKey: options.awsSecretKey,
|
|
12
|
-
awsAccessKey: options.awsAccessKey,
|
|
13
|
-
minioEndpoint: options.minioEndpoint,
|
|
14
|
-
provider: options.provider
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
async handleUpload(upload, _args, _context, info) {
|
|
18
|
-
const { uploadPlugin: { tags, type } } = info;
|
|
19
|
-
const readStream = upload.createReadStream();
|
|
20
|
-
const { filename, mimetype } = upload;
|
|
21
|
-
const rand = Math.random().toString(36).substring(2, 7) +
|
|
22
|
-
Math.random().toString(36).substring(2, 7);
|
|
23
|
-
const key = rand + '-' + uploadNames(filename);
|
|
24
|
-
const result = await this.streamer.upload({
|
|
25
|
-
readStream,
|
|
26
|
-
filename,
|
|
27
|
-
key,
|
|
28
|
-
bucket: this.options.bucketName
|
|
29
|
-
});
|
|
30
|
-
const url = result.upload.Location;
|
|
31
|
-
const { contentType, magic: { charset } } = result;
|
|
32
|
-
const typ = type || tags.type;
|
|
33
|
-
const mim = tags.mime
|
|
34
|
-
? tags.mime.trim().split(',').map((a) => a.trim())
|
|
35
|
-
: typ === 'image'
|
|
36
|
-
? ['image/jpg', 'image/jpeg', 'image/png', 'image/svg+xml']
|
|
37
|
-
: [];
|
|
38
|
-
if (mim.length && !mim.includes(contentType)) {
|
|
39
|
-
throw new Error(`UPLOAD_MIMETYPE ${mim.join(',')}`);
|
|
40
|
-
}
|
|
41
|
-
switch (typ) {
|
|
42
|
-
case 'image':
|
|
43
|
-
case 'upload':
|
|
44
|
-
return {
|
|
45
|
-
filename,
|
|
46
|
-
mime: contentType,
|
|
47
|
-
url
|
|
48
|
-
};
|
|
49
|
-
case 'attachment':
|
|
50
|
-
default:
|
|
51
|
-
return url;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
package/resolvers/uploads.d.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import type { GraphQLResolveInfo } from 'graphql';
|
|
2
|
-
import type { BucketProvider } from '@pgpmjs/types';
|
|
3
|
-
interface UploaderOptions {
|
|
4
|
-
bucketName: string;
|
|
5
|
-
awsRegion: string;
|
|
6
|
-
awsSecretKey: string;
|
|
7
|
-
awsAccessKey: string;
|
|
8
|
-
minioEndpoint?: string;
|
|
9
|
-
provider?: BucketProvider;
|
|
10
|
-
}
|
|
11
|
-
interface Upload {
|
|
12
|
-
createReadStream: () => NodeJS.ReadableStream;
|
|
13
|
-
filename: string;
|
|
14
|
-
mimetype: string;
|
|
15
|
-
encoding: string;
|
|
16
|
-
}
|
|
17
|
-
interface UploadPluginInfo {
|
|
18
|
-
tags: {
|
|
19
|
-
[key: string]: any;
|
|
20
|
-
};
|
|
21
|
-
type: string;
|
|
22
|
-
}
|
|
23
|
-
export declare class UploadHandler {
|
|
24
|
-
private options;
|
|
25
|
-
private streamer;
|
|
26
|
-
constructor(options: UploaderOptions);
|
|
27
|
-
handleUpload(upload: Upload, _args: any, _context: any, info: GraphQLResolveInfo & {
|
|
28
|
-
uploadPlugin: UploadPluginInfo;
|
|
29
|
-
}): Promise<any>;
|
|
30
|
-
}
|
|
31
|
-
export {};
|
package/resolvers/uploads.js
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.UploadHandler = void 0;
|
|
7
|
-
const s3_streamer_1 = __importDefault(require("@constructive-io/s3-streamer"));
|
|
8
|
-
const upload_names_1 = __importDefault(require("@constructive-io/upload-names"));
|
|
9
|
-
class UploadHandler {
|
|
10
|
-
options;
|
|
11
|
-
streamer;
|
|
12
|
-
constructor(options) {
|
|
13
|
-
this.options = options;
|
|
14
|
-
this.streamer = new s3_streamer_1.default({
|
|
15
|
-
defaultBucket: options.bucketName,
|
|
16
|
-
awsRegion: options.awsRegion,
|
|
17
|
-
awsSecretKey: options.awsSecretKey,
|
|
18
|
-
awsAccessKey: options.awsAccessKey,
|
|
19
|
-
minioEndpoint: options.minioEndpoint,
|
|
20
|
-
provider: options.provider
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
async handleUpload(upload, _args, _context, info) {
|
|
24
|
-
const { uploadPlugin: { tags, type } } = info;
|
|
25
|
-
const readStream = upload.createReadStream();
|
|
26
|
-
const { filename, mimetype } = upload;
|
|
27
|
-
const rand = Math.random().toString(36).substring(2, 7) +
|
|
28
|
-
Math.random().toString(36).substring(2, 7);
|
|
29
|
-
const key = rand + '-' + (0, upload_names_1.default)(filename);
|
|
30
|
-
const result = await this.streamer.upload({
|
|
31
|
-
readStream,
|
|
32
|
-
filename,
|
|
33
|
-
key,
|
|
34
|
-
bucket: this.options.bucketName
|
|
35
|
-
});
|
|
36
|
-
const url = result.upload.Location;
|
|
37
|
-
const { contentType, magic: { charset } } = result;
|
|
38
|
-
const typ = type || tags.type;
|
|
39
|
-
const mim = tags.mime
|
|
40
|
-
? tags.mime.trim().split(',').map((a) => a.trim())
|
|
41
|
-
: typ === 'image'
|
|
42
|
-
? ['image/jpg', 'image/jpeg', 'image/png', 'image/svg+xml']
|
|
43
|
-
: [];
|
|
44
|
-
if (mim.length && !mim.includes(contentType)) {
|
|
45
|
-
throw new Error(`UPLOAD_MIMETYPE ${mim.join(',')}`);
|
|
46
|
-
}
|
|
47
|
-
switch (typ) {
|
|
48
|
-
case 'image':
|
|
49
|
-
case 'upload':
|
|
50
|
-
return {
|
|
51
|
-
filename,
|
|
52
|
-
mime: contentType,
|
|
53
|
-
url
|
|
54
|
-
};
|
|
55
|
-
case 'attachment':
|
|
56
|
-
default:
|
|
57
|
-
return url;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
exports.UploadHandler = UploadHandler;
|