graphile-presigned-url-plugin 0.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/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 Dan Lynch <pyramation@gmail.com>
4
+ Copyright (c) 2025 Constructive <developers@constructive.io>
5
+ Copyright (c) 2020-present, Interweb, Inc.
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to deal
9
+ in the Software without restriction, including without limitation the rights
10
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be included in all
15
+ copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,93 @@
1
+ # graphile-presigned-url-plugin
2
+
3
+ Presigned URL upload plugin for PostGraphile v5.
4
+
5
+ ## Features
6
+
7
+ - `requestUploadUrl` mutation โ€” generates presigned PUT URLs for direct client-to-S3 upload
8
+ - `confirmUpload` mutation โ€” verifies upload and transitions file status to 'ready'
9
+ - `downloadUrl` computed field โ€” presigned GET URLs for private files, public URLs for public files
10
+ - Content-hash based S3 keys (SHA-256) with automatic deduplication
11
+ - Per-bucket MIME type and file size validation
12
+ - Upload request tracking for audit and rate limiting
13
+
14
+ ## Usage
15
+
16
+ ```typescript
17
+ import { PresignedUrlPreset } from 'graphile-presigned-url-plugin';
18
+ import { S3Client } from '@aws-sdk/client-s3';
19
+
20
+ const s3Client = new S3Client({ region: 'us-east-1' });
21
+
22
+ const preset = {
23
+ extends: [
24
+ PresignedUrlPreset({
25
+ s3: {
26
+ client: s3Client,
27
+ bucket: 'my-uploads',
28
+ publicUrlPrefix: 'https://cdn.example.com',
29
+ },
30
+ urlExpirySeconds: 900,
31
+ maxFileSize: 200 * 1024 * 1024,
32
+ }),
33
+ ],
34
+ };
35
+ ```
36
+
37
+ ---
38
+
39
+ ## Education and Tutorials
40
+
41
+ 1. ๐Ÿš€ [Quickstart: Getting Up and Running](https://constructive.io/learn/quickstart)
42
+ Get started with modular databases in minutes. Install prerequisites and deploy your first module.
43
+
44
+ 2. ๐Ÿ“ฆ [Modular PostgreSQL Development with Database Packages](https://constructive.io/learn/modular-postgres)
45
+ Learn to organize PostgreSQL projects with pgpm workspaces and reusable database modules.
46
+
47
+ 3. โœ๏ธ [Authoring Database Changes](https://constructive.io/learn/authoring-database-changes)
48
+ Master the workflow for adding, organizing, and managing database changes with pgpm.
49
+
50
+ 4. ๐Ÿงช [End-to-End PostgreSQL Testing with TypeScript](https://constructive.io/learn/e2e-postgres-testing)
51
+ Master end-to-end PostgreSQL testing with ephemeral databases, RLS testing, and CI/CD automation.
52
+
53
+ 5. โšก [Supabase Testing](https://constructive.io/learn/supabase)
54
+ Use TypeScript-first tools to test Supabase projects with realistic RLS, policies, and auth contexts.
55
+
56
+ 6. ๐Ÿ’ง [Drizzle ORM Testing](https://constructive.io/learn/drizzle-testing)
57
+ Run full-stack tests with Drizzle ORM, including database setup, teardown, and RLS enforcement.
58
+
59
+ 7. ๐Ÿ”ง [Troubleshooting](https://constructive.io/learn/troubleshooting)
60
+ Common issues and solutions for pgpm, PostgreSQL, and testing.
61
+
62
+ ## Related Constructive Tooling
63
+
64
+ ### ๐Ÿ“ฆ Package Management
65
+
66
+ * [pgpm](https://github.com/constructive-io/constructive/tree/main/pgpm/pgpm): **๐Ÿ–ฅ๏ธ PostgreSQL Package Manager** for modular Postgres development. Works with database workspaces, scaffolding, migrations, seeding, and installing database packages.
67
+
68
+ ### ๐Ÿงช Testing
69
+
70
+ * [pgsql-test](https://github.com/constructive-io/constructive/tree/main/postgres/pgsql-test): **๐Ÿ“Š Isolated testing environments** with per-test transaction rollbacksโ€”ideal for integration tests, complex migrations, and RLS simulation.
71
+ * [pgsql-seed](https://github.com/constructive-io/constructive/tree/main/postgres/pgsql-seed): **๐ŸŒฑ PostgreSQL seeding utilities** for CSV, JSON, SQL data loading, and pgpm deployment.
72
+ * [supabase-test](https://github.com/constructive-io/constructive/tree/main/postgres/supabase-test): **๐Ÿงช Supabase-native test harness** preconfigured for the local Supabase stackโ€”per-test rollbacks, JWT/role context helpers, and CI/GitHub Actions ready.
73
+ * [graphile-test](https://github.com/constructive-io/constructive/tree/main/graphile/graphile-test): **๐Ÿ” Authentication mocking** for Graphile-focused test helpers and emulating row-level security contexts.
74
+ * [pg-query-context](https://github.com/constructive-io/constructive/tree/main/postgres/pg-query-context): **๐Ÿ”’ Session context injection** to add session-local context (e.g., `SET LOCAL`) into queriesโ€”ideal for setting `role`, `jwt.claims`, and other session settings.
75
+
76
+ ### ๐Ÿง  Parsing & AST
77
+
78
+ * [pgsql-parser](https://www.npmjs.com/package/pgsql-parser): **๐Ÿ”„ SQL conversion engine** that interprets and converts PostgreSQL syntax.
79
+ * [libpg-query-node](https://www.npmjs.com/package/libpg-query): **๐ŸŒ‰ Node.js bindings** for `libpg_query`, converting SQL into parse trees.
80
+ * [pg-proto-parser](https://www.npmjs.com/package/pg-proto-parser): **๐Ÿ“ฆ Protobuf parser** for parsing PostgreSQL Protocol Buffers definitions to generate TypeScript interfaces, utility functions, and JSON mappings for enums.
81
+ * [@pgsql/enums](https://www.npmjs.com/package/@pgsql/enums): **๐Ÿท๏ธ TypeScript enums** for PostgreSQL AST for safe and ergonomic parsing logic.
82
+ * [@pgsql/types](https://www.npmjs.com/package/@pgsql/types): **๐Ÿ“ Type definitions** for PostgreSQL AST nodes in TypeScript.
83
+ * [@pgsql/utils](https://www.npmjs.com/package/@pgsql/utils): **๐Ÿ› ๏ธ AST utilities** for constructing and transforming PostgreSQL syntax trees.
84
+
85
+ ## Credits
86
+
87
+ **๐Ÿ›  Built by the [Constructive](https://constructive.io) team โ€” creators of modular Postgres tooling for secure, composable backends. If you like our work, contribute on [GitHub](https://github.com/constructive-io).**
88
+
89
+ ## Disclaimer
90
+
91
+ AS DESCRIBED IN THE LICENSES, THE SOFTWARE IS PROVIDED "AS IS", AT YOUR OWN RISK, AND WITHOUT WARRANTIES OF ANY KIND.
92
+
93
+ No developer or entity involved in creating this software will be liable for any claims or damages whatsoever associated with your use, inability to use, or your interaction with other users of the code, including any direct, indirect, incidental, special, exemplary, punitive or consequential damages, or loss of profits, cryptocurrencies, tokens, or anything else of value.
@@ -0,0 +1,27 @@
1
+ /**
2
+ * downloadUrl Computed Field Plugin
3
+ *
4
+ * Adds a `downloadUrl` computed field to File types in the GraphQL schema.
5
+ * For public files, returns the public URL prefix + key.
6
+ * For private files, generates a presigned GET URL.
7
+ *
8
+ * Detection: Uses the `@storageFiles` smart tag on the codec (table).
9
+ * The storage module generator in constructive-db sets this tag on the
10
+ * generated files table via a smart comment:
11
+ * COMMENT ON TABLE files IS E'@storageFiles\nStorage files table';
12
+ *
13
+ * This is explicit and reliable โ€” no duck-typing on column names.
14
+ */
15
+ import type { GraphileConfig } from 'graphile-config';
16
+ import type { PresignedUrlPluginOptions } from './types';
17
+ /**
18
+ * Creates the downloadUrl computed field plugin.
19
+ *
20
+ * This is a separate plugin from the main presigned URL plugin because it
21
+ * uses the GraphQLObjectType_fields hook (low-level) rather than extendSchema.
22
+ * The downloadUrl field needs to be added dynamically to whatever table is
23
+ * the storage module's files table, which we discover at schema-build time
24
+ * via the `@storageFiles` smart tag.
25
+ */
26
+ export declare function createDownloadUrlPlugin(options: PresignedUrlPluginOptions): GraphileConfig.Plugin;
27
+ export default createDownloadUrlPlugin;
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ /**
3
+ * downloadUrl Computed Field Plugin
4
+ *
5
+ * Adds a `downloadUrl` computed field to File types in the GraphQL schema.
6
+ * For public files, returns the public URL prefix + key.
7
+ * For private files, generates a presigned GET URL.
8
+ *
9
+ * Detection: Uses the `@storageFiles` smart tag on the codec (table).
10
+ * The storage module generator in constructive-db sets this tag on the
11
+ * generated files table via a smart comment:
12
+ * COMMENT ON TABLE files IS E'@storageFiles\nStorage files table';
13
+ *
14
+ * This is explicit and reliable โ€” no duck-typing on column names.
15
+ */
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.createDownloadUrlPlugin = createDownloadUrlPlugin;
18
+ const logger_1 = require("@pgpmjs/logger");
19
+ const s3_signer_1 = require("./s3-signer");
20
+ const storage_module_cache_1 = require("./storage-module-cache");
21
+ const log = new logger_1.Logger('graphile-presigned-url:download-url');
22
+ /**
23
+ * Creates the downloadUrl computed field plugin.
24
+ *
25
+ * This is a separate plugin from the main presigned URL plugin because it
26
+ * uses the GraphQLObjectType_fields hook (low-level) rather than extendSchema.
27
+ * The downloadUrl field needs to be added dynamically to whatever table is
28
+ * the storage module's files table, which we discover at schema-build time
29
+ * via the `@storageFiles` smart tag.
30
+ */
31
+ function createDownloadUrlPlugin(options) {
32
+ const { s3 } = options;
33
+ return {
34
+ name: 'PresignedUrlDownloadPlugin',
35
+ version: '0.1.0',
36
+ description: 'Adds downloadUrl computed field to File types tagged with @storageFiles',
37
+ schema: {
38
+ hooks: {
39
+ GraphQLObjectType_fields(fields, build, context) {
40
+ const { scope: { pgCodec, isPgClassType }, } = context;
41
+ // Only process PG class types (table row types)
42
+ if (!isPgClassType || !pgCodec || !pgCodec.attributes) {
43
+ return fields;
44
+ }
45
+ // Check for @storageFiles smart tag โ€” set by the storage module generator
46
+ const tags = pgCodec.extensions?.tags;
47
+ if (!tags?.storageFiles) {
48
+ return fields;
49
+ }
50
+ log.debug(`Adding downloadUrl field to type: ${pgCodec.name} (has @storageFiles tag)`);
51
+ const { graphql: { GraphQLString }, } = build;
52
+ return build.extend(fields, {
53
+ downloadUrl: context.fieldWithHooks({ fieldName: 'downloadUrl' }, {
54
+ description: 'URL to download this file. For public files, returns the public URL. ' +
55
+ 'For private files, returns a time-limited presigned URL.',
56
+ type: GraphQLString,
57
+ async resolve(parent, _args, context) {
58
+ const key = parent.key || parent.get?.('key');
59
+ const isPublic = parent.is_public ?? parent.get?.('is_public');
60
+ const filename = parent.filename || parent.get?.('filename');
61
+ const status = parent.status || parent.get?.('status');
62
+ if (!key)
63
+ return null;
64
+ // Only provide download URLs for ready/processed files
65
+ if (status !== 'ready' && status !== 'processed') {
66
+ return null;
67
+ }
68
+ if (isPublic && s3.publicUrlPrefix) {
69
+ // Public file: return direct URL
70
+ return `${s3.publicUrlPrefix}/${key}`;
71
+ }
72
+ // Resolve download URL expiry from storage module config (per-database)
73
+ let downloadUrlExpirySeconds = 3600; // fallback default
74
+ try {
75
+ const withPgClient = context.pgSettings
76
+ ? context.withPgClient
77
+ : null;
78
+ if (withPgClient) {
79
+ const config = await withPgClient(null, async (pgClient) => {
80
+ const dbResult = await pgClient.query(`SELECT jwt_private.current_database_id() AS id`);
81
+ const databaseId = dbResult.rows[0]?.id;
82
+ if (!databaseId)
83
+ return null;
84
+ return (0, storage_module_cache_1.getStorageModuleConfig)(pgClient, databaseId);
85
+ });
86
+ if (config) {
87
+ downloadUrlExpirySeconds = config.downloadUrlExpirySeconds;
88
+ }
89
+ }
90
+ }
91
+ catch {
92
+ // Fall back to default if config lookup fails
93
+ }
94
+ // Private file: generate presigned GET URL
95
+ return (0, s3_signer_1.generatePresignedGetUrl)(s3, key, downloadUrlExpirySeconds, filename || undefined);
96
+ },
97
+ }),
98
+ }, 'PresignedUrlDownloadPlugin adding downloadUrl field');
99
+ },
100
+ },
101
+ },
102
+ };
103
+ }
104
+ exports.default = createDownloadUrlPlugin;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * downloadUrl Computed Field Plugin
3
+ *
4
+ * Adds a `downloadUrl` computed field to File types in the GraphQL schema.
5
+ * For public files, returns the public URL prefix + key.
6
+ * For private files, generates a presigned GET URL.
7
+ *
8
+ * Detection: Uses the `@storageFiles` smart tag on the codec (table).
9
+ * The storage module generator in constructive-db sets this tag on the
10
+ * generated files table via a smart comment:
11
+ * COMMENT ON TABLE files IS E'@storageFiles\nStorage files table';
12
+ *
13
+ * This is explicit and reliable โ€” no duck-typing on column names.
14
+ */
15
+ import type { GraphileConfig } from 'graphile-config';
16
+ import type { PresignedUrlPluginOptions } from './types';
17
+ /**
18
+ * Creates the downloadUrl computed field plugin.
19
+ *
20
+ * This is a separate plugin from the main presigned URL plugin because it
21
+ * uses the GraphQLObjectType_fields hook (low-level) rather than extendSchema.
22
+ * The downloadUrl field needs to be added dynamically to whatever table is
23
+ * the storage module's files table, which we discover at schema-build time
24
+ * via the `@storageFiles` smart tag.
25
+ */
26
+ export declare function createDownloadUrlPlugin(options: PresignedUrlPluginOptions): GraphileConfig.Plugin;
27
+ export default createDownloadUrlPlugin;
@@ -0,0 +1,101 @@
1
+ /**
2
+ * downloadUrl Computed Field Plugin
3
+ *
4
+ * Adds a `downloadUrl` computed field to File types in the GraphQL schema.
5
+ * For public files, returns the public URL prefix + key.
6
+ * For private files, generates a presigned GET URL.
7
+ *
8
+ * Detection: Uses the `@storageFiles` smart tag on the codec (table).
9
+ * The storage module generator in constructive-db sets this tag on the
10
+ * generated files table via a smart comment:
11
+ * COMMENT ON TABLE files IS E'@storageFiles\nStorage files table';
12
+ *
13
+ * This is explicit and reliable โ€” no duck-typing on column names.
14
+ */
15
+ import { Logger } from '@pgpmjs/logger';
16
+ import { generatePresignedGetUrl } from './s3-signer';
17
+ import { getStorageModuleConfig } from './storage-module-cache';
18
+ const log = new Logger('graphile-presigned-url:download-url');
19
+ /**
20
+ * Creates the downloadUrl computed field plugin.
21
+ *
22
+ * This is a separate plugin from the main presigned URL plugin because it
23
+ * uses the GraphQLObjectType_fields hook (low-level) rather than extendSchema.
24
+ * The downloadUrl field needs to be added dynamically to whatever table is
25
+ * the storage module's files table, which we discover at schema-build time
26
+ * via the `@storageFiles` smart tag.
27
+ */
28
+ export function createDownloadUrlPlugin(options) {
29
+ const { s3 } = options;
30
+ return {
31
+ name: 'PresignedUrlDownloadPlugin',
32
+ version: '0.1.0',
33
+ description: 'Adds downloadUrl computed field to File types tagged with @storageFiles',
34
+ schema: {
35
+ hooks: {
36
+ GraphQLObjectType_fields(fields, build, context) {
37
+ const { scope: { pgCodec, isPgClassType }, } = context;
38
+ // Only process PG class types (table row types)
39
+ if (!isPgClassType || !pgCodec || !pgCodec.attributes) {
40
+ return fields;
41
+ }
42
+ // Check for @storageFiles smart tag โ€” set by the storage module generator
43
+ const tags = pgCodec.extensions?.tags;
44
+ if (!tags?.storageFiles) {
45
+ return fields;
46
+ }
47
+ log.debug(`Adding downloadUrl field to type: ${pgCodec.name} (has @storageFiles tag)`);
48
+ const { graphql: { GraphQLString }, } = build;
49
+ return build.extend(fields, {
50
+ downloadUrl: context.fieldWithHooks({ fieldName: 'downloadUrl' }, {
51
+ description: 'URL to download this file. For public files, returns the public URL. ' +
52
+ 'For private files, returns a time-limited presigned URL.',
53
+ type: GraphQLString,
54
+ async resolve(parent, _args, context) {
55
+ const key = parent.key || parent.get?.('key');
56
+ const isPublic = parent.is_public ?? parent.get?.('is_public');
57
+ const filename = parent.filename || parent.get?.('filename');
58
+ const status = parent.status || parent.get?.('status');
59
+ if (!key)
60
+ return null;
61
+ // Only provide download URLs for ready/processed files
62
+ if (status !== 'ready' && status !== 'processed') {
63
+ return null;
64
+ }
65
+ if (isPublic && s3.publicUrlPrefix) {
66
+ // Public file: return direct URL
67
+ return `${s3.publicUrlPrefix}/${key}`;
68
+ }
69
+ // Resolve download URL expiry from storage module config (per-database)
70
+ let downloadUrlExpirySeconds = 3600; // fallback default
71
+ try {
72
+ const withPgClient = context.pgSettings
73
+ ? context.withPgClient
74
+ : null;
75
+ if (withPgClient) {
76
+ const config = await withPgClient(null, async (pgClient) => {
77
+ const dbResult = await pgClient.query(`SELECT jwt_private.current_database_id() AS id`);
78
+ const databaseId = dbResult.rows[0]?.id;
79
+ if (!databaseId)
80
+ return null;
81
+ return getStorageModuleConfig(pgClient, databaseId);
82
+ });
83
+ if (config) {
84
+ downloadUrlExpirySeconds = config.downloadUrlExpirySeconds;
85
+ }
86
+ }
87
+ }
88
+ catch {
89
+ // Fall back to default if config lookup fails
90
+ }
91
+ // Private file: generate presigned GET URL
92
+ return generatePresignedGetUrl(s3, key, downloadUrlExpirySeconds, filename || undefined);
93
+ },
94
+ }),
95
+ }, 'PresignedUrlDownloadPlugin adding downloadUrl field');
96
+ },
97
+ },
98
+ },
99
+ };
100
+ }
101
+ export default createDownloadUrlPlugin;
package/esm/index.d.ts ADDED
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Presigned URL Plugin for PostGraphile v5
3
+ *
4
+ * Provides presigned URL upload capabilities for PostGraphile v5:
5
+ * - requestUploadUrl mutation (presigned PUT URL generation)
6
+ * - confirmUpload mutation (upload verification + status transition)
7
+ * - downloadUrl computed field (presigned GET URL / public URL)
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * import { PresignedUrlPreset } from 'graphile-presigned-url-plugin';
12
+ * import { S3Client } from '@aws-sdk/client-s3';
13
+ *
14
+ * const s3Client = new S3Client({ region: 'us-east-1' });
15
+ *
16
+ * const preset = {
17
+ * extends: [
18
+ * PresignedUrlPreset({
19
+ * s3: {
20
+ * client: s3Client,
21
+ * bucket: 'my-uploads',
22
+ * publicUrlPrefix: 'https://cdn.example.com',
23
+ * },
24
+ * }),
25
+ * ],
26
+ * };
27
+ * ```
28
+ */
29
+ export { PresignedUrlPlugin, createPresignedUrlPlugin } from './plugin';
30
+ export { createDownloadUrlPlugin } from './download-url-field';
31
+ export { PresignedUrlPreset } from './preset';
32
+ export { getStorageModuleConfig, getBucketConfig, clearStorageModuleCache, clearBucketCache } from './storage-module-cache';
33
+ export { generatePresignedPutUrl, generatePresignedGetUrl, headObject } from './s3-signer';
34
+ export type { BucketConfig, StorageModuleConfig, RequestUploadUrlInput, RequestUploadUrlPayload, ConfirmUploadInput, ConfirmUploadPayload, S3Config, PresignedUrlPluginOptions, } from './types';
package/esm/index.js ADDED
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Presigned URL Plugin for PostGraphile v5
3
+ *
4
+ * Provides presigned URL upload capabilities for PostGraphile v5:
5
+ * - requestUploadUrl mutation (presigned PUT URL generation)
6
+ * - confirmUpload mutation (upload verification + status transition)
7
+ * - downloadUrl computed field (presigned GET URL / public URL)
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * import { PresignedUrlPreset } from 'graphile-presigned-url-plugin';
12
+ * import { S3Client } from '@aws-sdk/client-s3';
13
+ *
14
+ * const s3Client = new S3Client({ region: 'us-east-1' });
15
+ *
16
+ * const preset = {
17
+ * extends: [
18
+ * PresignedUrlPreset({
19
+ * s3: {
20
+ * client: s3Client,
21
+ * bucket: 'my-uploads',
22
+ * publicUrlPrefix: 'https://cdn.example.com',
23
+ * },
24
+ * }),
25
+ * ],
26
+ * };
27
+ * ```
28
+ */
29
+ export { PresignedUrlPlugin, createPresignedUrlPlugin } from './plugin';
30
+ export { createDownloadUrlPlugin } from './download-url-field';
31
+ export { PresignedUrlPreset } from './preset';
32
+ export { getStorageModuleConfig, getBucketConfig, clearStorageModuleCache, clearBucketCache } from './storage-module-cache';
33
+ export { generatePresignedPutUrl, generatePresignedGetUrl, headObject } from './s3-signer';
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Presigned URL Plugin for PostGraphile v5
3
+ *
4
+ * Adds presigned URL upload support to PostGraphile v5:
5
+ *
6
+ * 1. `requestUploadUrl` mutation โ€” generates a presigned PUT URL for direct
7
+ * client-to-S3 upload. Checks bucket access via RLS, deduplicates by
8
+ * content hash, tracks the request in upload_requests.
9
+ *
10
+ * 2. `confirmUpload` mutation โ€” confirms a file was uploaded to S3, verifies
11
+ * the object exists with correct content-type, transitions file status
12
+ * from 'pending' to 'ready'.
13
+ *
14
+ * 3. `downloadUrl` computed field on File types โ€” generates presigned GET URLs
15
+ * for private files, returns public URL prefix + key for public files.
16
+ *
17
+ * Uses the extendSchema + grafast plan pattern (same as PublicKeySignature).
18
+ */
19
+ import type { GraphileConfig } from 'graphile-config';
20
+ import type { PresignedUrlPluginOptions } from './types';
21
+ export declare function createPresignedUrlPlugin(options: PresignedUrlPluginOptions): GraphileConfig.Plugin;
22
+ export declare const PresignedUrlPlugin: typeof createPresignedUrlPlugin;
23
+ export default PresignedUrlPlugin;