graphile-settings 4.18.10 → 4.20.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/bucket-provisioner-resolver.d.ts +19 -0
- package/bucket-provisioner-resolver.js +40 -0
- package/esm/bucket-provisioner-resolver.d.ts +19 -0
- package/esm/bucket-provisioner-resolver.js +37 -0
- package/esm/index.d.ts +2 -0
- package/esm/index.js +4 -0
- package/esm/presets/constructive-preset.d.ts +3 -0
- package/esm/presets/constructive-preset.js +16 -0
- package/esm/presigned-url-resolver.d.ts +59 -0
- package/esm/presigned-url-resolver.js +119 -0
- package/esm/upload-resolver.d.ts +1 -1
- package/esm/upload-resolver.js +3 -3
- package/index.d.ts +2 -0
- package/index.js +7 -1
- package/package.json +15 -11
- package/presets/constructive-preset.d.ts +3 -0
- package/presets/constructive-preset.js +16 -0
- package/presigned-url-resolver.d.ts +59 -0
- package/presigned-url-resolver.js +125 -0
- package/upload-resolver.d.ts +1 -1
- package/upload-resolver.js +3 -3
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bucket provisioner resolver for the Constructive bucket provisioner plugin.
|
|
3
|
+
*
|
|
4
|
+
* Reads CDN/S3 configuration from the standard env system
|
|
5
|
+
* (getEnvOptions -> pgpmDefaults + config files + env vars) and lazily
|
|
6
|
+
* returns a StorageConnectionConfig on first use.
|
|
7
|
+
*
|
|
8
|
+
* Follows the same lazy-init pattern as presigned-url-resolver.ts.
|
|
9
|
+
*/
|
|
10
|
+
import type { StorageConnectionConfig } from 'graphile-bucket-provisioner-plugin';
|
|
11
|
+
/**
|
|
12
|
+
* Lazily initialize and return the StorageConnectionConfig for the
|
|
13
|
+
* bucket provisioner plugin.
|
|
14
|
+
*
|
|
15
|
+
* Reads CDN config on first call via getEnvOptions() (which already merges
|
|
16
|
+
* pgpmDefaults -> config file -> env vars) and caches the result.
|
|
17
|
+
* Same CDN config source as presigned-url-resolver.ts.
|
|
18
|
+
*/
|
|
19
|
+
export declare function getBucketProvisionerConnection(): StorageConnectionConfig;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Bucket provisioner resolver for the Constructive bucket provisioner plugin.
|
|
4
|
+
*
|
|
5
|
+
* Reads CDN/S3 configuration from the standard env system
|
|
6
|
+
* (getEnvOptions -> pgpmDefaults + config files + env vars) and lazily
|
|
7
|
+
* returns a StorageConnectionConfig on first use.
|
|
8
|
+
*
|
|
9
|
+
* Follows the same lazy-init pattern as presigned-url-resolver.ts.
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.getBucketProvisionerConnection = getBucketProvisionerConnection;
|
|
13
|
+
const graphql_env_1 = require("@constructive-io/graphql-env");
|
|
14
|
+
const logger_1 = require("@pgpmjs/logger");
|
|
15
|
+
const log = new logger_1.Logger('bucket-provisioner-resolver');
|
|
16
|
+
let connectionConfig = null;
|
|
17
|
+
/**
|
|
18
|
+
* Lazily initialize and return the StorageConnectionConfig for the
|
|
19
|
+
* bucket provisioner plugin.
|
|
20
|
+
*
|
|
21
|
+
* Reads CDN config on first call via getEnvOptions() (which already merges
|
|
22
|
+
* pgpmDefaults -> config file -> env vars) and caches the result.
|
|
23
|
+
* Same CDN config source as presigned-url-resolver.ts.
|
|
24
|
+
*/
|
|
25
|
+
function getBucketProvisionerConnection() {
|
|
26
|
+
if (connectionConfig)
|
|
27
|
+
return connectionConfig;
|
|
28
|
+
const { cdn } = (0, graphql_env_1.getEnvOptions)();
|
|
29
|
+
// cdn is guaranteed populated — pgpmDefaults provides all CDN fields
|
|
30
|
+
const { provider, awsRegion, awsAccessKey, awsSecretKey, endpoint } = cdn;
|
|
31
|
+
log.info(`[bucket-provisioner-resolver] Initializing: provider=${provider} endpoint=${endpoint}`);
|
|
32
|
+
connectionConfig = {
|
|
33
|
+
provider: provider || 'minio',
|
|
34
|
+
region: awsRegion || 'us-east-1',
|
|
35
|
+
accessKeyId: awsAccessKey,
|
|
36
|
+
secretAccessKey: awsSecretKey,
|
|
37
|
+
...(endpoint ? { endpoint, forcePathStyle: true } : {}),
|
|
38
|
+
};
|
|
39
|
+
return connectionConfig;
|
|
40
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bucket provisioner resolver for the Constructive bucket provisioner plugin.
|
|
3
|
+
*
|
|
4
|
+
* Reads CDN/S3 configuration from the standard env system
|
|
5
|
+
* (getEnvOptions -> pgpmDefaults + config files + env vars) and lazily
|
|
6
|
+
* returns a StorageConnectionConfig on first use.
|
|
7
|
+
*
|
|
8
|
+
* Follows the same lazy-init pattern as presigned-url-resolver.ts.
|
|
9
|
+
*/
|
|
10
|
+
import type { StorageConnectionConfig } from 'graphile-bucket-provisioner-plugin';
|
|
11
|
+
/**
|
|
12
|
+
* Lazily initialize and return the StorageConnectionConfig for the
|
|
13
|
+
* bucket provisioner plugin.
|
|
14
|
+
*
|
|
15
|
+
* Reads CDN config on first call via getEnvOptions() (which already merges
|
|
16
|
+
* pgpmDefaults -> config file -> env vars) and caches the result.
|
|
17
|
+
* Same CDN config source as presigned-url-resolver.ts.
|
|
18
|
+
*/
|
|
19
|
+
export declare function getBucketProvisionerConnection(): StorageConnectionConfig;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bucket provisioner resolver for the Constructive bucket provisioner plugin.
|
|
3
|
+
*
|
|
4
|
+
* Reads CDN/S3 configuration from the standard env system
|
|
5
|
+
* (getEnvOptions -> pgpmDefaults + config files + env vars) and lazily
|
|
6
|
+
* returns a StorageConnectionConfig on first use.
|
|
7
|
+
*
|
|
8
|
+
* Follows the same lazy-init pattern as presigned-url-resolver.ts.
|
|
9
|
+
*/
|
|
10
|
+
import { getEnvOptions } from '@constructive-io/graphql-env';
|
|
11
|
+
import { Logger } from '@pgpmjs/logger';
|
|
12
|
+
const log = new Logger('bucket-provisioner-resolver');
|
|
13
|
+
let connectionConfig = null;
|
|
14
|
+
/**
|
|
15
|
+
* Lazily initialize and return the StorageConnectionConfig for the
|
|
16
|
+
* bucket provisioner plugin.
|
|
17
|
+
*
|
|
18
|
+
* Reads CDN config on first call via getEnvOptions() (which already merges
|
|
19
|
+
* pgpmDefaults -> config file -> env vars) and caches the result.
|
|
20
|
+
* Same CDN config source as presigned-url-resolver.ts.
|
|
21
|
+
*/
|
|
22
|
+
export function getBucketProvisionerConnection() {
|
|
23
|
+
if (connectionConfig)
|
|
24
|
+
return connectionConfig;
|
|
25
|
+
const { cdn } = getEnvOptions();
|
|
26
|
+
// cdn is guaranteed populated — pgpmDefaults provides all CDN fields
|
|
27
|
+
const { provider, awsRegion, awsAccessKey, awsSecretKey, endpoint } = cdn;
|
|
28
|
+
log.info(`[bucket-provisioner-resolver] Initializing: provider=${provider} endpoint=${endpoint}`);
|
|
29
|
+
connectionConfig = {
|
|
30
|
+
provider: provider || 'minio',
|
|
31
|
+
region: awsRegion || 'us-east-1',
|
|
32
|
+
accessKeyId: awsAccessKey,
|
|
33
|
+
secretAccessKey: awsSecretKey,
|
|
34
|
+
...(endpoint ? { endpoint, forcePathStyle: true } : {}),
|
|
35
|
+
};
|
|
36
|
+
return connectionConfig;
|
|
37
|
+
}
|
package/esm/index.d.ts
CHANGED
|
@@ -34,3 +34,5 @@ export * from './plugins/index';
|
|
|
34
34
|
export * from './presets/index';
|
|
35
35
|
export { makePgService };
|
|
36
36
|
export { streamToStorage } from './upload-resolver';
|
|
37
|
+
export { getPresignedUrlS3Config } from './presigned-url-resolver';
|
|
38
|
+
export { getBucketProvisionerConnection } from './bucket-provisioner-resolver';
|
package/esm/index.js
CHANGED
|
@@ -50,3 +50,7 @@ export * from './presets/index';
|
|
|
50
50
|
export { makePgService };
|
|
51
51
|
// Upload utilities
|
|
52
52
|
export { streamToStorage } from './upload-resolver';
|
|
53
|
+
// Presigned URL utilities
|
|
54
|
+
export { getPresignedUrlS3Config } from './presigned-url-resolver';
|
|
55
|
+
// Bucket provisioner utilities
|
|
56
|
+
export { getBucketProvisionerConnection } from './bucket-provisioner-resolver';
|
|
@@ -17,6 +17,9 @@ import type { GraphileConfig } from 'graphile-config';
|
|
|
17
17
|
* - PostGIS support (geometry/geography types, GeoJSON scalar — auto-detects PostGIS extension)
|
|
18
18
|
* - PostGIS connection filter operators (spatial filtering on geometry/geography columns)
|
|
19
19
|
* - Upload plugin (file upload to S3/MinIO for image, upload, attachment domain columns)
|
|
20
|
+
* - Presigned URL plugin (requestUploadUrl, confirmUpload mutations + downloadUrl computed field)
|
|
21
|
+
* - Bucket provisioner plugin (auto-provisions S3 buckets on @storageBuckets table mutations,
|
|
22
|
+
* CORS management, provisionBucket mutation for manual/retry)
|
|
20
23
|
* - SQL expression validator (validates @sqlExpression columns in mutations)
|
|
21
24
|
* - PG type mappings (maps custom types like email, url to GraphQL scalars)
|
|
22
25
|
* - pgvector search (auto-discovers vector columns: filter fields, distance computed fields,
|
|
@@ -3,8 +3,12 @@ import { MinimalPreset, InflektPreset, ConflictDetectorPreset, InflectorLoggerPr
|
|
|
3
3
|
import { UnifiedSearchPreset, createMatchesOperatorFactory, createTrgmOperatorFactories } from 'graphile-search';
|
|
4
4
|
import { GraphilePostgisPreset, createPostgisOperatorFactory } from 'graphile-postgis';
|
|
5
5
|
import { UploadPreset } from 'graphile-upload-plugin';
|
|
6
|
+
import { PresignedUrlPreset } from 'graphile-presigned-url-plugin';
|
|
7
|
+
import { BucketProvisionerPreset } from 'graphile-bucket-provisioner-plugin';
|
|
6
8
|
import { SqlExpressionValidatorPreset } from 'graphile-sql-expression-validator';
|
|
7
9
|
import { constructiveUploadFieldDefinitions } from '../upload-resolver';
|
|
10
|
+
import { getPresignedUrlS3Config, createBucketNameResolver, createEnsureBucketProvisioned, getAllowedOrigins } from '../presigned-url-resolver';
|
|
11
|
+
import { getBucketProvisionerConnection } from '../bucket-provisioner-resolver';
|
|
8
12
|
/**
|
|
9
13
|
* Constructive PostGraphile v5 Preset
|
|
10
14
|
*
|
|
@@ -23,6 +27,9 @@ import { constructiveUploadFieldDefinitions } from '../upload-resolver';
|
|
|
23
27
|
* - PostGIS support (geometry/geography types, GeoJSON scalar — auto-detects PostGIS extension)
|
|
24
28
|
* - PostGIS connection filter operators (spatial filtering on geometry/geography columns)
|
|
25
29
|
* - Upload plugin (file upload to S3/MinIO for image, upload, attachment domain columns)
|
|
30
|
+
* - Presigned URL plugin (requestUploadUrl, confirmUpload mutations + downloadUrl computed field)
|
|
31
|
+
* - Bucket provisioner plugin (auto-provisions S3 buckets on @storageBuckets table mutations,
|
|
32
|
+
* CORS management, provisionBucket mutation for manual/retry)
|
|
26
33
|
* - SQL expression validator (validates @sqlExpression columns in mutations)
|
|
27
34
|
* - PG type mappings (maps custom types like email, url to GraphQL scalars)
|
|
28
35
|
* - pgvector search (auto-discovers vector columns: filter fields, distance computed fields,
|
|
@@ -70,6 +77,15 @@ export const ConstructivePreset = {
|
|
|
70
77
|
uploadFieldDefinitions: constructiveUploadFieldDefinitions,
|
|
71
78
|
maxFileSize: 10 * 1024 * 1024, // 10MB
|
|
72
79
|
}),
|
|
80
|
+
PresignedUrlPreset({
|
|
81
|
+
s3: getPresignedUrlS3Config,
|
|
82
|
+
resolveBucketName: createBucketNameResolver(),
|
|
83
|
+
ensureBucketProvisioned: createEnsureBucketProvisioned(),
|
|
84
|
+
}),
|
|
85
|
+
BucketProvisionerPreset({
|
|
86
|
+
connection: getBucketProvisionerConnection,
|
|
87
|
+
allowedOrigins: getAllowedOrigins(),
|
|
88
|
+
}),
|
|
73
89
|
SqlExpressionValidatorPreset(),
|
|
74
90
|
PgTypeMappingsPreset,
|
|
75
91
|
RequiredInputPreset,
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Presigned URL resolver for the Constructive presigned URL plugin.
|
|
3
|
+
*
|
|
4
|
+
* Reads CDN/S3 configuration from the standard env system
|
|
5
|
+
* (getEnvOptions → pgpmDefaults + config files + env vars) and lazily
|
|
6
|
+
* initializes an S3Client on first use.
|
|
7
|
+
*
|
|
8
|
+
* Also provides a per-database bucket name resolver that derives the
|
|
9
|
+
* S3 bucket name from the database UUID + a configurable prefix.
|
|
10
|
+
*
|
|
11
|
+
* Follows the same lazy-init pattern as upload-resolver.ts.
|
|
12
|
+
*/
|
|
13
|
+
import type { S3Config, BucketNameResolver, EnsureBucketProvisioned } from 'graphile-presigned-url-plugin';
|
|
14
|
+
/**
|
|
15
|
+
* Lazily initialize and return the S3Config for the presigned URL plugin.
|
|
16
|
+
*
|
|
17
|
+
* Reads CDN config on first call via getEnvOptions() (which already merges
|
|
18
|
+
* pgpmDefaults → config file → env vars), creates an S3Client, and caches
|
|
19
|
+
* the result. Same CDN config as upload-resolver.ts.
|
|
20
|
+
*
|
|
21
|
+
* NOTE: The `bucket` field here is the global fallback bucket name
|
|
22
|
+
* (from BUCKET_NAME env var). When `resolveBucketName` is provided,
|
|
23
|
+
* per-database bucket names take precedence for all S3 operations.
|
|
24
|
+
*/
|
|
25
|
+
export declare function getPresignedUrlS3Config(): S3Config;
|
|
26
|
+
/**
|
|
27
|
+
* Create a per-database bucket name resolver.
|
|
28
|
+
*
|
|
29
|
+
* Uses the BUCKET_NAME env var as a prefix. For each database, the S3 bucket
|
|
30
|
+
* name becomes `{prefix}-{databaseId}` (e.g., "myapp-abc123def456").
|
|
31
|
+
*
|
|
32
|
+
* In local development with MinIO (default BUCKET_NAME="test-bucket"),
|
|
33
|
+
* all databases share the same bucket for simplicity — the resolver
|
|
34
|
+
* returns the prefix as-is when it looks like a local dev bucket.
|
|
35
|
+
*
|
|
36
|
+
* In production, set BUCKET_NAME to your org prefix (e.g., "myapp")
|
|
37
|
+
* and each database gets its own isolated S3 bucket.
|
|
38
|
+
*/
|
|
39
|
+
export declare function createBucketNameResolver(): BucketNameResolver;
|
|
40
|
+
/**
|
|
41
|
+
* Resolve CORS allowed origins from the env/config system.
|
|
42
|
+
*
|
|
43
|
+
* Reads SERVER_ORIGIN from the standard env hierarchy
|
|
44
|
+
* (pgpmDefaults → config file → env vars) and wraps it in an array.
|
|
45
|
+
* Falls back to ['http://localhost:3000'] for local development.
|
|
46
|
+
*/
|
|
47
|
+
export declare function getAllowedOrigins(): string[];
|
|
48
|
+
/**
|
|
49
|
+
* Create a lazy bucket provisioner callback for the presigned URL plugin.
|
|
50
|
+
*
|
|
51
|
+
* On the first upload to an S3 bucket that doesn't exist yet, this callback
|
|
52
|
+
* uses the BucketProvisioner to create and fully configure the bucket
|
|
53
|
+
* (Block Public Access, CORS, policies, lifecycle rules for temp buckets).
|
|
54
|
+
*
|
|
55
|
+
* Uses the same S3 connection config as the bucket provisioner plugin
|
|
56
|
+
* (getBucketProvisionerConnection) and reads CORS origins from
|
|
57
|
+
* SERVER_ORIGIN env var (falls back to localhost for local dev).
|
|
58
|
+
*/
|
|
59
|
+
export declare function createEnsureBucketProvisioned(): EnsureBucketProvisioned;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Presigned URL resolver for the Constructive presigned URL plugin.
|
|
3
|
+
*
|
|
4
|
+
* Reads CDN/S3 configuration from the standard env system
|
|
5
|
+
* (getEnvOptions → pgpmDefaults + config files + env vars) and lazily
|
|
6
|
+
* initializes an S3Client on first use.
|
|
7
|
+
*
|
|
8
|
+
* Also provides a per-database bucket name resolver that derives the
|
|
9
|
+
* S3 bucket name from the database UUID + a configurable prefix.
|
|
10
|
+
*
|
|
11
|
+
* Follows the same lazy-init pattern as upload-resolver.ts.
|
|
12
|
+
*/
|
|
13
|
+
import { S3Client } from '@aws-sdk/client-s3';
|
|
14
|
+
import { getEnvOptions } from '@constructive-io/graphql-env';
|
|
15
|
+
import { Logger } from '@pgpmjs/logger';
|
|
16
|
+
import { BucketProvisioner } from '@constructive-io/bucket-provisioner';
|
|
17
|
+
import { getBucketProvisionerConnection } from './bucket-provisioner-resolver';
|
|
18
|
+
const log = new Logger('presigned-url-resolver');
|
|
19
|
+
let s3Config = null;
|
|
20
|
+
/**
|
|
21
|
+
* Lazily initialize and return the S3Config for the presigned URL plugin.
|
|
22
|
+
*
|
|
23
|
+
* Reads CDN config on first call via getEnvOptions() (which already merges
|
|
24
|
+
* pgpmDefaults → config file → env vars), creates an S3Client, and caches
|
|
25
|
+
* the result. Same CDN config as upload-resolver.ts.
|
|
26
|
+
*
|
|
27
|
+
* NOTE: The `bucket` field here is the global fallback bucket name
|
|
28
|
+
* (from BUCKET_NAME env var). When `resolveBucketName` is provided,
|
|
29
|
+
* per-database bucket names take precedence for all S3 operations.
|
|
30
|
+
*/
|
|
31
|
+
export function getPresignedUrlS3Config() {
|
|
32
|
+
if (s3Config)
|
|
33
|
+
return s3Config;
|
|
34
|
+
const { cdn } = getEnvOptions();
|
|
35
|
+
// cdn is guaranteed populated — pgpmDefaults provides all CDN fields
|
|
36
|
+
const { bucketName, awsRegion, awsAccessKey, awsSecretKey, endpoint, publicUrlPrefix } = cdn;
|
|
37
|
+
log.info(`[presigned-url-resolver] Initializing: bucket=${bucketName} endpoint=${endpoint}`);
|
|
38
|
+
const client = new S3Client({
|
|
39
|
+
region: awsRegion,
|
|
40
|
+
credentials: { accessKeyId: awsAccessKey, secretAccessKey: awsSecretKey },
|
|
41
|
+
...(endpoint ? { endpoint, forcePathStyle: true } : {}),
|
|
42
|
+
});
|
|
43
|
+
s3Config = {
|
|
44
|
+
client,
|
|
45
|
+
bucket: bucketName,
|
|
46
|
+
region: awsRegion,
|
|
47
|
+
publicUrlPrefix,
|
|
48
|
+
...(endpoint ? { endpoint, forcePathStyle: true } : {}),
|
|
49
|
+
};
|
|
50
|
+
return s3Config;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Create a per-database bucket name resolver.
|
|
54
|
+
*
|
|
55
|
+
* Uses the BUCKET_NAME env var as a prefix. For each database, the S3 bucket
|
|
56
|
+
* name becomes `{prefix}-{databaseId}` (e.g., "myapp-abc123def456").
|
|
57
|
+
*
|
|
58
|
+
* In local development with MinIO (default BUCKET_NAME="test-bucket"),
|
|
59
|
+
* all databases share the same bucket for simplicity — the resolver
|
|
60
|
+
* returns the prefix as-is when it looks like a local dev bucket.
|
|
61
|
+
*
|
|
62
|
+
* In production, set BUCKET_NAME to your org prefix (e.g., "myapp")
|
|
63
|
+
* and each database gets its own isolated S3 bucket.
|
|
64
|
+
*/
|
|
65
|
+
export function createBucketNameResolver() {
|
|
66
|
+
const { cdn } = getEnvOptions();
|
|
67
|
+
const prefix = cdn?.bucketName || 'test-bucket';
|
|
68
|
+
return (databaseId) => {
|
|
69
|
+
return `${prefix}-${databaseId}`;
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Resolve CORS allowed origins from the env/config system.
|
|
74
|
+
*
|
|
75
|
+
* Reads SERVER_ORIGIN from the standard env hierarchy
|
|
76
|
+
* (pgpmDefaults → config file → env vars) and wraps it in an array.
|
|
77
|
+
* Falls back to ['http://localhost:3000'] for local development.
|
|
78
|
+
*/
|
|
79
|
+
export function getAllowedOrigins() {
|
|
80
|
+
const { server } = getEnvOptions();
|
|
81
|
+
if (server?.origin)
|
|
82
|
+
return [server.origin];
|
|
83
|
+
return ['*'];
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Create a lazy bucket provisioner callback for the presigned URL plugin.
|
|
87
|
+
*
|
|
88
|
+
* On the first upload to an S3 bucket that doesn't exist yet, this callback
|
|
89
|
+
* uses the BucketProvisioner to create and fully configure the bucket
|
|
90
|
+
* (Block Public Access, CORS, policies, lifecycle rules for temp buckets).
|
|
91
|
+
*
|
|
92
|
+
* Uses the same S3 connection config as the bucket provisioner plugin
|
|
93
|
+
* (getBucketProvisionerConnection) and reads CORS origins from
|
|
94
|
+
* SERVER_ORIGIN env var (falls back to localhost for local dev).
|
|
95
|
+
*/
|
|
96
|
+
export function createEnsureBucketProvisioned() {
|
|
97
|
+
let provisioner = null;
|
|
98
|
+
return async (bucketName, accessType, databaseId, allowedOrigins) => {
|
|
99
|
+
// Per-database origins from storage_module, falling back to global SERVER_ORIGIN
|
|
100
|
+
const effectiveOrigins = (allowedOrigins && allowedOrigins.length > 0)
|
|
101
|
+
? allowedOrigins
|
|
102
|
+
: getAllowedOrigins();
|
|
103
|
+
if (!provisioner) {
|
|
104
|
+
provisioner = new BucketProvisioner({
|
|
105
|
+
connection: getBucketProvisionerConnection(),
|
|
106
|
+
allowedOrigins: effectiveOrigins,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
log.info(`[lazy-provision] Provisioning S3 bucket "${bucketName}" ` +
|
|
110
|
+
`(type=${accessType}) for database ${databaseId}`);
|
|
111
|
+
await provisioner.provision({
|
|
112
|
+
bucketName,
|
|
113
|
+
accessType,
|
|
114
|
+
versioning: false,
|
|
115
|
+
allowedOrigins: effectiveOrigins,
|
|
116
|
+
});
|
|
117
|
+
log.info(`[lazy-provision] S3 bucket "${bucketName}" provisioned successfully`);
|
|
118
|
+
};
|
|
119
|
+
}
|
package/esm/upload-resolver.d.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* AWS_REGION - AWS region (default: 'us-east-1')
|
|
14
14
|
* AWS_ACCESS_KEY - access key (default: 'minioadmin')
|
|
15
15
|
* AWS_SECRET_KEY - secret key (default: 'minioadmin')
|
|
16
|
-
*
|
|
16
|
+
* CDN_ENDPOINT - S3-compatible endpoint (default: 'http://localhost:9000')
|
|
17
17
|
*/
|
|
18
18
|
import type { Readable } from 'stream';
|
|
19
19
|
import type { UploadFieldDefinition } from 'graphile-upload-plugin';
|
package/esm/upload-resolver.js
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* AWS_REGION - AWS region (default: 'us-east-1')
|
|
14
14
|
* AWS_ACCESS_KEY - access key (default: 'minioadmin')
|
|
15
15
|
* AWS_SECRET_KEY - secret key (default: 'minioadmin')
|
|
16
|
-
*
|
|
16
|
+
* CDN_ENDPOINT - S3-compatible endpoint (default: 'http://localhost:9000')
|
|
17
17
|
*/
|
|
18
18
|
import Streamer from '@constructive-io/s3-streamer';
|
|
19
19
|
import uploadNames from '@constructive-io/upload-names';
|
|
@@ -34,7 +34,7 @@ function getStreamer() {
|
|
|
34
34
|
const awsRegion = cdn.awsRegion || 'us-east-1';
|
|
35
35
|
const awsAccessKey = cdn.awsAccessKey || 'minioadmin';
|
|
36
36
|
const awsSecretKey = cdn.awsSecretKey || 'minioadmin';
|
|
37
|
-
const
|
|
37
|
+
const endpoint = cdn.endpoint || 'http://localhost:9000';
|
|
38
38
|
if (process.env.NODE_ENV === 'production') {
|
|
39
39
|
if (!cdn.awsAccessKey || !cdn.awsSecretKey) {
|
|
40
40
|
log.warn('[upload-resolver] WARNING: Using default credentials in production.');
|
|
@@ -46,7 +46,7 @@ function getStreamer() {
|
|
|
46
46
|
awsRegion,
|
|
47
47
|
awsSecretKey,
|
|
48
48
|
awsAccessKey,
|
|
49
|
-
|
|
49
|
+
endpoint,
|
|
50
50
|
provider,
|
|
51
51
|
});
|
|
52
52
|
return streamer;
|
package/index.d.ts
CHANGED
|
@@ -34,3 +34,5 @@ export * from './plugins/index';
|
|
|
34
34
|
export * from './presets/index';
|
|
35
35
|
export { makePgService };
|
|
36
36
|
export { streamToStorage } from './upload-resolver';
|
|
37
|
+
export { getPresignedUrlS3Config } from './presigned-url-resolver';
|
|
38
|
+
export { getBucketProvisionerConnection } from './bucket-provisioner-resolver';
|
package/index.js
CHANGED
|
@@ -42,7 +42,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
42
42
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
43
43
|
};
|
|
44
44
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
-
exports.streamToStorage = exports.makePgService = exports.ConstructivePreset = void 0;
|
|
45
|
+
exports.getBucketProvisionerConnection = exports.getPresignedUrlS3Config = exports.streamToStorage = exports.makePgService = exports.ConstructivePreset = void 0;
|
|
46
46
|
const pg_1 = require("postgraphile/adaptors/pg");
|
|
47
47
|
Object.defineProperty(exports, "makePgService", { enumerable: true, get: function () { return pg_1.makePgService; } });
|
|
48
48
|
// Import modules for type augmentation
|
|
@@ -65,3 +65,9 @@ __exportStar(require("./presets/index"), exports);
|
|
|
65
65
|
// Upload utilities
|
|
66
66
|
var upload_resolver_1 = require("./upload-resolver");
|
|
67
67
|
Object.defineProperty(exports, "streamToStorage", { enumerable: true, get: function () { return upload_resolver_1.streamToStorage; } });
|
|
68
|
+
// Presigned URL utilities
|
|
69
|
+
var presigned_url_resolver_1 = require("./presigned-url-resolver");
|
|
70
|
+
Object.defineProperty(exports, "getPresignedUrlS3Config", { enumerable: true, get: function () { return presigned_url_resolver_1.getPresignedUrlS3Config; } });
|
|
71
|
+
// Bucket provisioner utilities
|
|
72
|
+
var bucket_provisioner_resolver_1 = require("./bucket-provisioner-resolver");
|
|
73
|
+
Object.defineProperty(exports, "getBucketProvisionerConnection", { enumerable: true, get: function () { return bucket_provisioner_resolver_1.getBucketProvisionerConnection; } });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "graphile-settings",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.20.0",
|
|
4
4
|
"author": "Constructive <developers@constructive.io>",
|
|
5
5
|
"description": "graphile settings",
|
|
6
6
|
"main": "index.js",
|
|
@@ -29,26 +29,30 @@
|
|
|
29
29
|
"test:watch": "jest --watch"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@
|
|
33
|
-
"@constructive-io/
|
|
34
|
-
"@constructive-io/
|
|
32
|
+
"@aws-sdk/client-s3": "^3.1009.0",
|
|
33
|
+
"@constructive-io/bucket-provisioner": "^0.2.0",
|
|
34
|
+
"@constructive-io/graphql-env": "^3.5.4",
|
|
35
|
+
"@constructive-io/graphql-types": "^3.4.4",
|
|
36
|
+
"@constructive-io/s3-streamer": "^2.17.4",
|
|
35
37
|
"@constructive-io/upload-names": "^2.10.2",
|
|
36
38
|
"@dataplan/json": "1.0.0",
|
|
37
39
|
"@dataplan/pg": "1.0.0",
|
|
38
40
|
"@graphile-contrib/pg-many-to-many": "2.0.0-rc.2",
|
|
39
41
|
"@pgpmjs/logger": "^2.5.2",
|
|
40
|
-
"@pgpmjs/types": "^2.
|
|
42
|
+
"@pgpmjs/types": "^2.21.0",
|
|
41
43
|
"@pgsql/quotes": "^17.1.0",
|
|
42
44
|
"cors": "^2.8.6",
|
|
43
45
|
"express": "^5.2.1",
|
|
44
46
|
"grafast": "1.0.0",
|
|
45
47
|
"grafserv": "1.0.0",
|
|
48
|
+
"graphile-bucket-provisioner-plugin": "0.2.0",
|
|
46
49
|
"graphile-build": "5.0.0",
|
|
47
50
|
"graphile-build-pg": "5.0.0",
|
|
48
51
|
"graphile-config": "1.0.0",
|
|
49
|
-
"graphile-connection-filter": "^1.
|
|
50
|
-
"graphile-postgis": "^2.
|
|
51
|
-
"graphile-
|
|
52
|
+
"graphile-connection-filter": "^1.4.0",
|
|
53
|
+
"graphile-postgis": "^2.10.0",
|
|
54
|
+
"graphile-presigned-url-plugin": "^0.4.0",
|
|
55
|
+
"graphile-search": "^1.6.0",
|
|
52
56
|
"graphile-sql-expression-validator": "^2.6.2",
|
|
53
57
|
"graphile-upload-plugin": "^2.5.2",
|
|
54
58
|
"graphile-utils": "5.0.0",
|
|
@@ -67,10 +71,10 @@
|
|
|
67
71
|
"@types/express": "^5.0.6",
|
|
68
72
|
"@types/pg": "^8.18.0",
|
|
69
73
|
"@types/request-ip": "^0.0.41",
|
|
70
|
-
"graphile-test": "^4.
|
|
74
|
+
"graphile-test": "^4.8.0",
|
|
71
75
|
"makage": "^0.3.0",
|
|
72
76
|
"nodemon": "^3.1.14",
|
|
73
|
-
"pgsql-test": "^4.
|
|
77
|
+
"pgsql-test": "^4.8.0",
|
|
74
78
|
"ts-node": "^10.9.2"
|
|
75
79
|
},
|
|
76
80
|
"keywords": [
|
|
@@ -80,5 +84,5 @@
|
|
|
80
84
|
"constructive",
|
|
81
85
|
"graphql"
|
|
82
86
|
],
|
|
83
|
-
"gitHead": "
|
|
87
|
+
"gitHead": "3bf7c522cf9f9d2595750ac7cea81d470b3e6c30"
|
|
84
88
|
}
|
|
@@ -17,6 +17,9 @@ import type { GraphileConfig } from 'graphile-config';
|
|
|
17
17
|
* - PostGIS support (geometry/geography types, GeoJSON scalar — auto-detects PostGIS extension)
|
|
18
18
|
* - PostGIS connection filter operators (spatial filtering on geometry/geography columns)
|
|
19
19
|
* - Upload plugin (file upload to S3/MinIO for image, upload, attachment domain columns)
|
|
20
|
+
* - Presigned URL plugin (requestUploadUrl, confirmUpload mutations + downloadUrl computed field)
|
|
21
|
+
* - Bucket provisioner plugin (auto-provisions S3 buckets on @storageBuckets table mutations,
|
|
22
|
+
* CORS management, provisionBucket mutation for manual/retry)
|
|
20
23
|
* - SQL expression validator (validates @sqlExpression columns in mutations)
|
|
21
24
|
* - PG type mappings (maps custom types like email, url to GraphQL scalars)
|
|
22
25
|
* - pgvector search (auto-discovers vector columns: filter fields, distance computed fields,
|
|
@@ -6,8 +6,12 @@ const plugins_1 = require("../plugins");
|
|
|
6
6
|
const graphile_search_1 = require("graphile-search");
|
|
7
7
|
const graphile_postgis_1 = require("graphile-postgis");
|
|
8
8
|
const graphile_upload_plugin_1 = require("graphile-upload-plugin");
|
|
9
|
+
const graphile_presigned_url_plugin_1 = require("graphile-presigned-url-plugin");
|
|
10
|
+
const graphile_bucket_provisioner_plugin_1 = require("graphile-bucket-provisioner-plugin");
|
|
9
11
|
const graphile_sql_expression_validator_1 = require("graphile-sql-expression-validator");
|
|
10
12
|
const upload_resolver_1 = require("../upload-resolver");
|
|
13
|
+
const presigned_url_resolver_1 = require("../presigned-url-resolver");
|
|
14
|
+
const bucket_provisioner_resolver_1 = require("../bucket-provisioner-resolver");
|
|
11
15
|
/**
|
|
12
16
|
* Constructive PostGraphile v5 Preset
|
|
13
17
|
*
|
|
@@ -26,6 +30,9 @@ const upload_resolver_1 = require("../upload-resolver");
|
|
|
26
30
|
* - PostGIS support (geometry/geography types, GeoJSON scalar — auto-detects PostGIS extension)
|
|
27
31
|
* - PostGIS connection filter operators (spatial filtering on geometry/geography columns)
|
|
28
32
|
* - Upload plugin (file upload to S3/MinIO for image, upload, attachment domain columns)
|
|
33
|
+
* - Presigned URL plugin (requestUploadUrl, confirmUpload mutations + downloadUrl computed field)
|
|
34
|
+
* - Bucket provisioner plugin (auto-provisions S3 buckets on @storageBuckets table mutations,
|
|
35
|
+
* CORS management, provisionBucket mutation for manual/retry)
|
|
29
36
|
* - SQL expression validator (validates @sqlExpression columns in mutations)
|
|
30
37
|
* - PG type mappings (maps custom types like email, url to GraphQL scalars)
|
|
31
38
|
* - pgvector search (auto-discovers vector columns: filter fields, distance computed fields,
|
|
@@ -73,6 +80,15 @@ exports.ConstructivePreset = {
|
|
|
73
80
|
uploadFieldDefinitions: upload_resolver_1.constructiveUploadFieldDefinitions,
|
|
74
81
|
maxFileSize: 10 * 1024 * 1024, // 10MB
|
|
75
82
|
}),
|
|
83
|
+
(0, graphile_presigned_url_plugin_1.PresignedUrlPreset)({
|
|
84
|
+
s3: presigned_url_resolver_1.getPresignedUrlS3Config,
|
|
85
|
+
resolveBucketName: (0, presigned_url_resolver_1.createBucketNameResolver)(),
|
|
86
|
+
ensureBucketProvisioned: (0, presigned_url_resolver_1.createEnsureBucketProvisioned)(),
|
|
87
|
+
}),
|
|
88
|
+
(0, graphile_bucket_provisioner_plugin_1.BucketProvisionerPreset)({
|
|
89
|
+
connection: bucket_provisioner_resolver_1.getBucketProvisionerConnection,
|
|
90
|
+
allowedOrigins: (0, presigned_url_resolver_1.getAllowedOrigins)(),
|
|
91
|
+
}),
|
|
76
92
|
(0, graphile_sql_expression_validator_1.SqlExpressionValidatorPreset)(),
|
|
77
93
|
plugins_1.PgTypeMappingsPreset,
|
|
78
94
|
plugins_1.RequiredInputPreset,
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Presigned URL resolver for the Constructive presigned URL plugin.
|
|
3
|
+
*
|
|
4
|
+
* Reads CDN/S3 configuration from the standard env system
|
|
5
|
+
* (getEnvOptions → pgpmDefaults + config files + env vars) and lazily
|
|
6
|
+
* initializes an S3Client on first use.
|
|
7
|
+
*
|
|
8
|
+
* Also provides a per-database bucket name resolver that derives the
|
|
9
|
+
* S3 bucket name from the database UUID + a configurable prefix.
|
|
10
|
+
*
|
|
11
|
+
* Follows the same lazy-init pattern as upload-resolver.ts.
|
|
12
|
+
*/
|
|
13
|
+
import type { S3Config, BucketNameResolver, EnsureBucketProvisioned } from 'graphile-presigned-url-plugin';
|
|
14
|
+
/**
|
|
15
|
+
* Lazily initialize and return the S3Config for the presigned URL plugin.
|
|
16
|
+
*
|
|
17
|
+
* Reads CDN config on first call via getEnvOptions() (which already merges
|
|
18
|
+
* pgpmDefaults → config file → env vars), creates an S3Client, and caches
|
|
19
|
+
* the result. Same CDN config as upload-resolver.ts.
|
|
20
|
+
*
|
|
21
|
+
* NOTE: The `bucket` field here is the global fallback bucket name
|
|
22
|
+
* (from BUCKET_NAME env var). When `resolveBucketName` is provided,
|
|
23
|
+
* per-database bucket names take precedence for all S3 operations.
|
|
24
|
+
*/
|
|
25
|
+
export declare function getPresignedUrlS3Config(): S3Config;
|
|
26
|
+
/**
|
|
27
|
+
* Create a per-database bucket name resolver.
|
|
28
|
+
*
|
|
29
|
+
* Uses the BUCKET_NAME env var as a prefix. For each database, the S3 bucket
|
|
30
|
+
* name becomes `{prefix}-{databaseId}` (e.g., "myapp-abc123def456").
|
|
31
|
+
*
|
|
32
|
+
* In local development with MinIO (default BUCKET_NAME="test-bucket"),
|
|
33
|
+
* all databases share the same bucket for simplicity — the resolver
|
|
34
|
+
* returns the prefix as-is when it looks like a local dev bucket.
|
|
35
|
+
*
|
|
36
|
+
* In production, set BUCKET_NAME to your org prefix (e.g., "myapp")
|
|
37
|
+
* and each database gets its own isolated S3 bucket.
|
|
38
|
+
*/
|
|
39
|
+
export declare function createBucketNameResolver(): BucketNameResolver;
|
|
40
|
+
/**
|
|
41
|
+
* Resolve CORS allowed origins from the env/config system.
|
|
42
|
+
*
|
|
43
|
+
* Reads SERVER_ORIGIN from the standard env hierarchy
|
|
44
|
+
* (pgpmDefaults → config file → env vars) and wraps it in an array.
|
|
45
|
+
* Falls back to ['http://localhost:3000'] for local development.
|
|
46
|
+
*/
|
|
47
|
+
export declare function getAllowedOrigins(): string[];
|
|
48
|
+
/**
|
|
49
|
+
* Create a lazy bucket provisioner callback for the presigned URL plugin.
|
|
50
|
+
*
|
|
51
|
+
* On the first upload to an S3 bucket that doesn't exist yet, this callback
|
|
52
|
+
* uses the BucketProvisioner to create and fully configure the bucket
|
|
53
|
+
* (Block Public Access, CORS, policies, lifecycle rules for temp buckets).
|
|
54
|
+
*
|
|
55
|
+
* Uses the same S3 connection config as the bucket provisioner plugin
|
|
56
|
+
* (getBucketProvisionerConnection) and reads CORS origins from
|
|
57
|
+
* SERVER_ORIGIN env var (falls back to localhost for local dev).
|
|
58
|
+
*/
|
|
59
|
+
export declare function createEnsureBucketProvisioned(): EnsureBucketProvisioned;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Presigned URL resolver for the Constructive presigned URL plugin.
|
|
4
|
+
*
|
|
5
|
+
* Reads CDN/S3 configuration from the standard env system
|
|
6
|
+
* (getEnvOptions → pgpmDefaults + config files + env vars) and lazily
|
|
7
|
+
* initializes an S3Client on first use.
|
|
8
|
+
*
|
|
9
|
+
* Also provides a per-database bucket name resolver that derives the
|
|
10
|
+
* S3 bucket name from the database UUID + a configurable prefix.
|
|
11
|
+
*
|
|
12
|
+
* Follows the same lazy-init pattern as upload-resolver.ts.
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.getPresignedUrlS3Config = getPresignedUrlS3Config;
|
|
16
|
+
exports.createBucketNameResolver = createBucketNameResolver;
|
|
17
|
+
exports.getAllowedOrigins = getAllowedOrigins;
|
|
18
|
+
exports.createEnsureBucketProvisioned = createEnsureBucketProvisioned;
|
|
19
|
+
const client_s3_1 = require("@aws-sdk/client-s3");
|
|
20
|
+
const graphql_env_1 = require("@constructive-io/graphql-env");
|
|
21
|
+
const logger_1 = require("@pgpmjs/logger");
|
|
22
|
+
const bucket_provisioner_1 = require("@constructive-io/bucket-provisioner");
|
|
23
|
+
const bucket_provisioner_resolver_1 = require("./bucket-provisioner-resolver");
|
|
24
|
+
const log = new logger_1.Logger('presigned-url-resolver');
|
|
25
|
+
let s3Config = null;
|
|
26
|
+
/**
|
|
27
|
+
* Lazily initialize and return the S3Config for the presigned URL plugin.
|
|
28
|
+
*
|
|
29
|
+
* Reads CDN config on first call via getEnvOptions() (which already merges
|
|
30
|
+
* pgpmDefaults → config file → env vars), creates an S3Client, and caches
|
|
31
|
+
* the result. Same CDN config as upload-resolver.ts.
|
|
32
|
+
*
|
|
33
|
+
* NOTE: The `bucket` field here is the global fallback bucket name
|
|
34
|
+
* (from BUCKET_NAME env var). When `resolveBucketName` is provided,
|
|
35
|
+
* per-database bucket names take precedence for all S3 operations.
|
|
36
|
+
*/
|
|
37
|
+
function getPresignedUrlS3Config() {
|
|
38
|
+
if (s3Config)
|
|
39
|
+
return s3Config;
|
|
40
|
+
const { cdn } = (0, graphql_env_1.getEnvOptions)();
|
|
41
|
+
// cdn is guaranteed populated — pgpmDefaults provides all CDN fields
|
|
42
|
+
const { bucketName, awsRegion, awsAccessKey, awsSecretKey, endpoint, publicUrlPrefix } = cdn;
|
|
43
|
+
log.info(`[presigned-url-resolver] Initializing: bucket=${bucketName} endpoint=${endpoint}`);
|
|
44
|
+
const client = new client_s3_1.S3Client({
|
|
45
|
+
region: awsRegion,
|
|
46
|
+
credentials: { accessKeyId: awsAccessKey, secretAccessKey: awsSecretKey },
|
|
47
|
+
...(endpoint ? { endpoint, forcePathStyle: true } : {}),
|
|
48
|
+
});
|
|
49
|
+
s3Config = {
|
|
50
|
+
client,
|
|
51
|
+
bucket: bucketName,
|
|
52
|
+
region: awsRegion,
|
|
53
|
+
publicUrlPrefix,
|
|
54
|
+
...(endpoint ? { endpoint, forcePathStyle: true } : {}),
|
|
55
|
+
};
|
|
56
|
+
return s3Config;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Create a per-database bucket name resolver.
|
|
60
|
+
*
|
|
61
|
+
* Uses the BUCKET_NAME env var as a prefix. For each database, the S3 bucket
|
|
62
|
+
* name becomes `{prefix}-{databaseId}` (e.g., "myapp-abc123def456").
|
|
63
|
+
*
|
|
64
|
+
* In local development with MinIO (default BUCKET_NAME="test-bucket"),
|
|
65
|
+
* all databases share the same bucket for simplicity — the resolver
|
|
66
|
+
* returns the prefix as-is when it looks like a local dev bucket.
|
|
67
|
+
*
|
|
68
|
+
* In production, set BUCKET_NAME to your org prefix (e.g., "myapp")
|
|
69
|
+
* and each database gets its own isolated S3 bucket.
|
|
70
|
+
*/
|
|
71
|
+
function createBucketNameResolver() {
|
|
72
|
+
const { cdn } = (0, graphql_env_1.getEnvOptions)();
|
|
73
|
+
const prefix = cdn?.bucketName || 'test-bucket';
|
|
74
|
+
return (databaseId) => {
|
|
75
|
+
return `${prefix}-${databaseId}`;
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Resolve CORS allowed origins from the env/config system.
|
|
80
|
+
*
|
|
81
|
+
* Reads SERVER_ORIGIN from the standard env hierarchy
|
|
82
|
+
* (pgpmDefaults → config file → env vars) and wraps it in an array.
|
|
83
|
+
* Falls back to ['http://localhost:3000'] for local development.
|
|
84
|
+
*/
|
|
85
|
+
function getAllowedOrigins() {
|
|
86
|
+
const { server } = (0, graphql_env_1.getEnvOptions)();
|
|
87
|
+
if (server?.origin)
|
|
88
|
+
return [server.origin];
|
|
89
|
+
return ['*'];
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Create a lazy bucket provisioner callback for the presigned URL plugin.
|
|
93
|
+
*
|
|
94
|
+
* On the first upload to an S3 bucket that doesn't exist yet, this callback
|
|
95
|
+
* uses the BucketProvisioner to create and fully configure the bucket
|
|
96
|
+
* (Block Public Access, CORS, policies, lifecycle rules for temp buckets).
|
|
97
|
+
*
|
|
98
|
+
* Uses the same S3 connection config as the bucket provisioner plugin
|
|
99
|
+
* (getBucketProvisionerConnection) and reads CORS origins from
|
|
100
|
+
* SERVER_ORIGIN env var (falls back to localhost for local dev).
|
|
101
|
+
*/
|
|
102
|
+
function createEnsureBucketProvisioned() {
|
|
103
|
+
let provisioner = null;
|
|
104
|
+
return async (bucketName, accessType, databaseId, allowedOrigins) => {
|
|
105
|
+
// Per-database origins from storage_module, falling back to global SERVER_ORIGIN
|
|
106
|
+
const effectiveOrigins = (allowedOrigins && allowedOrigins.length > 0)
|
|
107
|
+
? allowedOrigins
|
|
108
|
+
: getAllowedOrigins();
|
|
109
|
+
if (!provisioner) {
|
|
110
|
+
provisioner = new bucket_provisioner_1.BucketProvisioner({
|
|
111
|
+
connection: (0, bucket_provisioner_resolver_1.getBucketProvisionerConnection)(),
|
|
112
|
+
allowedOrigins: effectiveOrigins,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
log.info(`[lazy-provision] Provisioning S3 bucket "${bucketName}" ` +
|
|
116
|
+
`(type=${accessType}) for database ${databaseId}`);
|
|
117
|
+
await provisioner.provision({
|
|
118
|
+
bucketName,
|
|
119
|
+
accessType,
|
|
120
|
+
versioning: false,
|
|
121
|
+
allowedOrigins: effectiveOrigins,
|
|
122
|
+
});
|
|
123
|
+
log.info(`[lazy-provision] S3 bucket "${bucketName}" provisioned successfully`);
|
|
124
|
+
};
|
|
125
|
+
}
|
package/upload-resolver.d.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* AWS_REGION - AWS region (default: 'us-east-1')
|
|
14
14
|
* AWS_ACCESS_KEY - access key (default: 'minioadmin')
|
|
15
15
|
* AWS_SECRET_KEY - secret key (default: 'minioadmin')
|
|
16
|
-
*
|
|
16
|
+
* CDN_ENDPOINT - S3-compatible endpoint (default: 'http://localhost:9000')
|
|
17
17
|
*/
|
|
18
18
|
import type { Readable } from 'stream';
|
|
19
19
|
import type { UploadFieldDefinition } from 'graphile-upload-plugin';
|
package/upload-resolver.js
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* AWS_REGION - AWS region (default: 'us-east-1')
|
|
15
15
|
* AWS_ACCESS_KEY - access key (default: 'minioadmin')
|
|
16
16
|
* AWS_SECRET_KEY - secret key (default: 'minioadmin')
|
|
17
|
-
*
|
|
17
|
+
* CDN_ENDPOINT - S3-compatible endpoint (default: 'http://localhost:9000')
|
|
18
18
|
*/
|
|
19
19
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
20
20
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
@@ -41,7 +41,7 @@ function getStreamer() {
|
|
|
41
41
|
const awsRegion = cdn.awsRegion || 'us-east-1';
|
|
42
42
|
const awsAccessKey = cdn.awsAccessKey || 'minioadmin';
|
|
43
43
|
const awsSecretKey = cdn.awsSecretKey || 'minioadmin';
|
|
44
|
-
const
|
|
44
|
+
const endpoint = cdn.endpoint || 'http://localhost:9000';
|
|
45
45
|
if (process.env.NODE_ENV === 'production') {
|
|
46
46
|
if (!cdn.awsAccessKey || !cdn.awsSecretKey) {
|
|
47
47
|
log.warn('[upload-resolver] WARNING: Using default credentials in production.');
|
|
@@ -53,7 +53,7 @@ function getStreamer() {
|
|
|
53
53
|
awsRegion,
|
|
54
54
|
awsSecretKey,
|
|
55
55
|
awsAccessKey,
|
|
56
|
-
|
|
56
|
+
endpoint,
|
|
57
57
|
provider,
|
|
58
58
|
});
|
|
59
59
|
return streamer;
|