feat: add graphile-bucket-provisioner-plugin + wire into ConstructivePreset#962
Merged
pyramation merged 6 commits intomainfrom Apr 4, 2026
Merged
Conversation
… bucket provisioning library
…kets on bucket table mutations - PostGraphile v5 plugin with two provisioning pathways: 1. Auto-provisioning hook on create mutations tagged with @storagebuckets 2. Explicit provisionBucket GraphQL mutation for manual/retry provisioning - Reads per-database endpoint/provider/publicUrlPrefix overrides from storage_module table - Lazy S3 config resolution (function-based, cached after first call) - Graceful error handling (provisioning failures logged, never fail the mutation) - Custom bucket naming via prefix or resolveBucketName function - 46 passing tests covering plugin structure, mutation callback, auto-provisioning hook, connection config resolution, error handling, and bucket name resolution - Added to CI test matrix
Contributor
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
|
All alerts resolved. Learn more about Socket for GitHub. This PR previously contained dependency changes with security issues that have been resolved, removed, or ignored. |
…Options - Add bucket-provisioner-resolver.ts in graphile-settings (lazy init via getEnvOptions, same pattern as presigned-url-resolver.ts) - Wire BucketProvisionerPreset into constructive-preset.ts with lazy connection getter - Update JSDoc examples in bucket-provisioner-plugin to show getEnvOptions pattern instead of raw process.env - Export getBucketProvisionerConnection from graphile-settings index
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
New PostGraphile v5 plugin that hooks into bucket creation mutations to automatically provision S3-compatible buckets using
@constructive-io/bucket-provisioner.Two provisioning pathways:
create*mutations on tables tagged with@storageBucketsto provision S3 buckets after the DB row is createdprovisionBucketmutation — GraphQL mutation for manual/retry provisioningAlso adds
packages/bucket-provisioner,packages/upload-client, and the new plugin to the CI test matrix.Preset Integration (latest)
Wires
BucketProvisionerPresetintoConstructivePresetfollowing the same lazy-init pattern as the presigned URL plugin:bucket-provisioner-resolver.ts— reads CDN config viagetEnvOptions()from@constructive-io/graphql-env, lazily creates and caches aStorageConnectionConfigon first useconstructive-preset.ts— passesgetBucketProvisionerConnectionas a function ref (not called), so env vars are only read when the first provisioning operation runsgetEnvOptions()pattern instead of rawprocess.envUpdates since last revision
schema-snapshot.test.ts.snapnow includes the newprovisionBucketmutation,ProvisionBucketInput, andProvisionBucketPayloadtypes added by the preset wiring. This confirms the plugin correctly extends the GraphQL schema when included inConstructivePreset.Review & Testing Checklist for Human
allowedOrigins: ['http://localhost:3000']hardcoded in preset (constructive-preset.ts:94) — this is a dev default. Verify this is acceptable for production or if it should come fromgetEnvOptions()/ a config value instead.plugin.ts:264-268— bucket schema/table names are interpolated into a query string via"${storageModule.buckets_schema}"."${storageModule.buckets_table}". Values come from the trustedstorage_moduletable, but verify this is acceptable vs. parameterized queries.resolveConnection()mutates the passed-inoptionsobject (plugin.ts:82-86) — it replacesoptions.connection(the lazy getter function) with the resolved value for caching. This is a side effect on the caller's object. Confirm this is intentional.grafast,graphile-utils,bucket-provisioner, and logger are all mocked. No integration tests against a real PostGraphile instance. Consider whether this gives sufficient confidence for the plugin's hook-based behavior.provisionBucketmutation,ProvisionBucketInput, andProvisionBucketPayload. Spot-check that no existing types were accidentally removed or altered.Recommended test plan: Deploy with a local PostGraphile + MinIO setup, run a
createBucketmutation on a@storageBuckets-tagged table, and verify both the DB row and S3 bucket are created. Then test the failure case (e.g., bad S3 credentials) to confirm the mutation still succeeds and the error is logged.Notes
bucket-provisionerbranch — not new dependency additions.provisionBucketForRowhelper queriesSTORAGE_MODULE_QUERYfor endpoint/provider overrides, but in the explicit mutation path this same query is also run earlier to find the bucket table. Minor redundancy, not a bug.bucket-provisioner-resolver.tsfollows the exact same pattern aspresigned-url-resolver.ts(module-level cache, lazy init on first call viagetEnvOptions()).CDNOptions.providertype ('s3' | 'minio' | 'gcs') is a subset ofStorageConnectionConfig.provider('s3' | 'minio' | 'r2' | 'gcs' | 'spaces'), so the cast in the resolver is safe.Link to Devin session: https://app.devin.ai/sessions/4c882ba2dfbf4045adf85fb83cde6f77
Requested by: @pyramation