graphile-presigned-url-plugin 0.11.0 → 0.12.1
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/plugin.d.ts +7 -4
- package/esm/plugin.js +54 -5
- package/package.json +2 -2
- package/plugin.d.ts +7 -4
- package/plugin.js +54 -5
package/esm/plugin.d.ts
CHANGED
|
@@ -9,11 +9,14 @@
|
|
|
9
9
|
* 2. Upload fields — adds `requestUploadUrl` and `requestBulkUploadUrls` fields
|
|
10
10
|
* on `@storageBuckets`-tagged types, so clients upload via the typed bucket API.
|
|
11
11
|
*
|
|
12
|
-
* 3.
|
|
12
|
+
* 3. Mutation entry points — adds per-bucket mutation fields on the root Mutation
|
|
13
|
+
* type (e.g., `appBucket(key: "public"): AppBucket`), so upload operations
|
|
14
|
+
* can be accessed as proper GraphQL mutations instead of queries.
|
|
13
15
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
16
|
+
* 4. downloadUrl — handled by download-url-field.ts (separate plugin).
|
|
17
|
+
*
|
|
18
|
+
* Scope resolution uses the codec's schema/table name matched against
|
|
19
|
+
* cached storage module configs.
|
|
17
20
|
*/
|
|
18
21
|
import type { GraphileConfig } from 'graphile-config';
|
|
19
22
|
import 'graphile-build';
|
package/esm/plugin.js
CHANGED
|
@@ -9,11 +9,14 @@
|
|
|
9
9
|
* 2. Upload fields — adds `requestUploadUrl` and `requestBulkUploadUrls` fields
|
|
10
10
|
* on `@storageBuckets`-tagged types, so clients upload via the typed bucket API.
|
|
11
11
|
*
|
|
12
|
-
* 3.
|
|
12
|
+
* 3. Mutation entry points — adds per-bucket mutation fields on the root Mutation
|
|
13
|
+
* type (e.g., `appBucket(key: "public"): AppBucket`), so upload operations
|
|
14
|
+
* can be accessed as proper GraphQL mutations instead of queries.
|
|
13
15
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
16
|
+
* 4. downloadUrl — handled by download-url-field.ts (separate plugin).
|
|
17
|
+
*
|
|
18
|
+
* Scope resolution uses the codec's schema/table name matched against
|
|
19
|
+
* cached storage module configs.
|
|
17
20
|
*/
|
|
18
21
|
import { context as grafastContext, lambda, object } from 'grafast';
|
|
19
22
|
import 'graphile-build';
|
|
@@ -111,7 +114,53 @@ export function createPresignedUrlPlugin(options) {
|
|
|
111
114
|
* Add requestUploadUrl and requestBulkUploadUrls fields on @storageBuckets types.
|
|
112
115
|
*/
|
|
113
116
|
GraphQLObjectType_fields(fields, build, context) {
|
|
114
|
-
const { scope: { pgCodec, isPgClassType }, } = context;
|
|
117
|
+
const { scope: { pgCodec, isPgClassType, isRootMutation }, } = context;
|
|
118
|
+
// --- Path 1: Add per-bucket mutation entry points on root Mutation ---
|
|
119
|
+
if (isRootMutation) {
|
|
120
|
+
const { graphql: { GraphQLString, GraphQLNonNull }, } = build;
|
|
121
|
+
const bucketCodecs = Object.values(build.input.pgRegistry.pgCodecs).filter((codec) => codec.attributes && codec.extensions?.tags?.storageBuckets);
|
|
122
|
+
if (bucketCodecs.length === 0)
|
|
123
|
+
return fields;
|
|
124
|
+
const newFields = {};
|
|
125
|
+
for (const codec of bucketCodecs) {
|
|
126
|
+
const typeName = build.inflection.tableType(codec);
|
|
127
|
+
const bucketType = build.getTypeByName(typeName);
|
|
128
|
+
if (!bucketType) {
|
|
129
|
+
log.debug(`Skipping mutation entry point for ${codec.name}: type ${typeName} not found`);
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
const fieldName = typeName.charAt(0).toLowerCase() + typeName.slice(1);
|
|
133
|
+
const hasOwnerId = !!codec.attributes.owner_id;
|
|
134
|
+
// Find the PgResource for this codec so we can return a proper PgSelectSingleStep
|
|
135
|
+
const bucketResource = Object.values(build.input.pgRegistry.pgResources).find((r) => r.codec === codec && !r.isUnique && !r.isVirtual && !r.parameters);
|
|
136
|
+
if (!bucketResource) {
|
|
137
|
+
log.debug(`Skipping mutation entry point for ${codec.name}: no PgResource found`);
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
log.debug(`Adding mutation entry point "${fieldName}" for bucket type ${typeName} (entity-scoped=${hasOwnerId})`);
|
|
141
|
+
newFields[fieldName] = context.fieldWithHooks({ fieldName }, {
|
|
142
|
+
description: `Look up a ${typeName} by key for mutation operations (upload, etc.).`,
|
|
143
|
+
type: bucketType,
|
|
144
|
+
args: {
|
|
145
|
+
key: { type: new GraphQLNonNull(GraphQLString), description: 'Bucket key (e.g., "public", "private")' },
|
|
146
|
+
...(hasOwnerId
|
|
147
|
+
? { ownerId: { type: new GraphQLNonNull(GraphQLString), description: 'Owner entity ID (required for entity-scoped buckets)' } }
|
|
148
|
+
: {}),
|
|
149
|
+
},
|
|
150
|
+
plan(_$mutation, fieldArgs) {
|
|
151
|
+
const spec = {
|
|
152
|
+
key: fieldArgs.getRaw('key'),
|
|
153
|
+
};
|
|
154
|
+
if (hasOwnerId) {
|
|
155
|
+
spec.owner_id = fieldArgs.getRaw('ownerId');
|
|
156
|
+
}
|
|
157
|
+
return bucketResource.find(spec).single();
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
return build.extend(fields, newFields, 'PresignedUrlPlugin adding per-bucket mutation entry points');
|
|
162
|
+
}
|
|
163
|
+
// --- Path 2: Add upload fields on @storageBuckets types ---
|
|
115
164
|
if (!isPgClassType || !pgCodec || !pgCodec.attributes) {
|
|
116
165
|
return fields;
|
|
117
166
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "graphile-presigned-url-plugin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.1",
|
|
4
4
|
"description": "Presigned URL upload plugin for PostGraphile v5 — requestUploadUrl mutation and downloadUrl computed field",
|
|
5
5
|
"author": "Constructive <developers@constructive.io>",
|
|
6
6
|
"homepage": "https://github.com/constructive-io/constructive",
|
|
@@ -60,5 +60,5 @@
|
|
|
60
60
|
"@types/node": "^22.19.11",
|
|
61
61
|
"makage": "^0.1.10"
|
|
62
62
|
},
|
|
63
|
-
"gitHead": "
|
|
63
|
+
"gitHead": "3491da5ae42fc87daf9b7c39c8735fcae51218a1"
|
|
64
64
|
}
|
package/plugin.d.ts
CHANGED
|
@@ -9,11 +9,14 @@
|
|
|
9
9
|
* 2. Upload fields — adds `requestUploadUrl` and `requestBulkUploadUrls` fields
|
|
10
10
|
* on `@storageBuckets`-tagged types, so clients upload via the typed bucket API.
|
|
11
11
|
*
|
|
12
|
-
* 3.
|
|
12
|
+
* 3. Mutation entry points — adds per-bucket mutation fields on the root Mutation
|
|
13
|
+
* type (e.g., `appBucket(key: "public"): AppBucket`), so upload operations
|
|
14
|
+
* can be accessed as proper GraphQL mutations instead of queries.
|
|
13
15
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
16
|
+
* 4. downloadUrl — handled by download-url-field.ts (separate plugin).
|
|
17
|
+
*
|
|
18
|
+
* Scope resolution uses the codec's schema/table name matched against
|
|
19
|
+
* cached storage module configs.
|
|
17
20
|
*/
|
|
18
21
|
import type { GraphileConfig } from 'graphile-config';
|
|
19
22
|
import 'graphile-build';
|
package/plugin.js
CHANGED
|
@@ -10,11 +10,14 @@
|
|
|
10
10
|
* 2. Upload fields — adds `requestUploadUrl` and `requestBulkUploadUrls` fields
|
|
11
11
|
* on `@storageBuckets`-tagged types, so clients upload via the typed bucket API.
|
|
12
12
|
*
|
|
13
|
-
* 3.
|
|
13
|
+
* 3. Mutation entry points — adds per-bucket mutation fields on the root Mutation
|
|
14
|
+
* type (e.g., `appBucket(key: "public"): AppBucket`), so upload operations
|
|
15
|
+
* can be accessed as proper GraphQL mutations instead of queries.
|
|
14
16
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
17
|
+
* 4. downloadUrl — handled by download-url-field.ts (separate plugin).
|
|
18
|
+
*
|
|
19
|
+
* Scope resolution uses the codec's schema/table name matched against
|
|
20
|
+
* cached storage module configs.
|
|
18
21
|
*/
|
|
19
22
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
23
|
exports.PresignedUrlPlugin = void 0;
|
|
@@ -115,7 +118,53 @@ function createPresignedUrlPlugin(options) {
|
|
|
115
118
|
* Add requestUploadUrl and requestBulkUploadUrls fields on @storageBuckets types.
|
|
116
119
|
*/
|
|
117
120
|
GraphQLObjectType_fields(fields, build, context) {
|
|
118
|
-
const { scope: { pgCodec, isPgClassType }, } = context;
|
|
121
|
+
const { scope: { pgCodec, isPgClassType, isRootMutation }, } = context;
|
|
122
|
+
// --- Path 1: Add per-bucket mutation entry points on root Mutation ---
|
|
123
|
+
if (isRootMutation) {
|
|
124
|
+
const { graphql: { GraphQLString, GraphQLNonNull }, } = build;
|
|
125
|
+
const bucketCodecs = Object.values(build.input.pgRegistry.pgCodecs).filter((codec) => codec.attributes && codec.extensions?.tags?.storageBuckets);
|
|
126
|
+
if (bucketCodecs.length === 0)
|
|
127
|
+
return fields;
|
|
128
|
+
const newFields = {};
|
|
129
|
+
for (const codec of bucketCodecs) {
|
|
130
|
+
const typeName = build.inflection.tableType(codec);
|
|
131
|
+
const bucketType = build.getTypeByName(typeName);
|
|
132
|
+
if (!bucketType) {
|
|
133
|
+
log.debug(`Skipping mutation entry point for ${codec.name}: type ${typeName} not found`);
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
const fieldName = typeName.charAt(0).toLowerCase() + typeName.slice(1);
|
|
137
|
+
const hasOwnerId = !!codec.attributes.owner_id;
|
|
138
|
+
// Find the PgResource for this codec so we can return a proper PgSelectSingleStep
|
|
139
|
+
const bucketResource = Object.values(build.input.pgRegistry.pgResources).find((r) => r.codec === codec && !r.isUnique && !r.isVirtual && !r.parameters);
|
|
140
|
+
if (!bucketResource) {
|
|
141
|
+
log.debug(`Skipping mutation entry point for ${codec.name}: no PgResource found`);
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
log.debug(`Adding mutation entry point "${fieldName}" for bucket type ${typeName} (entity-scoped=${hasOwnerId})`);
|
|
145
|
+
newFields[fieldName] = context.fieldWithHooks({ fieldName }, {
|
|
146
|
+
description: `Look up a ${typeName} by key for mutation operations (upload, etc.).`,
|
|
147
|
+
type: bucketType,
|
|
148
|
+
args: {
|
|
149
|
+
key: { type: new GraphQLNonNull(GraphQLString), description: 'Bucket key (e.g., "public", "private")' },
|
|
150
|
+
...(hasOwnerId
|
|
151
|
+
? { ownerId: { type: new GraphQLNonNull(GraphQLString), description: 'Owner entity ID (required for entity-scoped buckets)' } }
|
|
152
|
+
: {}),
|
|
153
|
+
},
|
|
154
|
+
plan(_$mutation, fieldArgs) {
|
|
155
|
+
const spec = {
|
|
156
|
+
key: fieldArgs.getRaw('key'),
|
|
157
|
+
};
|
|
158
|
+
if (hasOwnerId) {
|
|
159
|
+
spec.owner_id = fieldArgs.getRaw('ownerId');
|
|
160
|
+
}
|
|
161
|
+
return bucketResource.find(spec).single();
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
return build.extend(fields, newFields, 'PresignedUrlPlugin adding per-bucket mutation entry points');
|
|
166
|
+
}
|
|
167
|
+
// --- Path 2: Add upload fields on @storageBuckets types ---
|
|
119
168
|
if (!isPgClassType || !pgCodec || !pgCodec.attributes) {
|
|
120
169
|
return fields;
|
|
121
170
|
}
|