graphile-bucket-provisioner-plugin 1.10.0 → 1.11.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/plugin.js +19 -8
- package/package.json +2 -2
- package/plugin.js +19 -8
package/esm/plugin.js
CHANGED
|
@@ -81,6 +81,17 @@ const ALL_STORAGE_MODULES_QUERY = `
|
|
|
81
81
|
LEFT JOIN metaschema_public.schema es ON es.id = et.schema_id
|
|
82
82
|
WHERE sm.database_id = $1
|
|
83
83
|
`;
|
|
84
|
+
/**
|
|
85
|
+
* Run a query against a grafast `withPgClient` client.
|
|
86
|
+
*
|
|
87
|
+
* That client's `query` takes the `{ text, values }` object form (the same
|
|
88
|
+
* shape the presigned-url plugin uses) — NOT node-pg's positional
|
|
89
|
+
* `(text, params)` args, which surface as "A query must have either text or a
|
|
90
|
+
* name" at runtime.
|
|
91
|
+
*/
|
|
92
|
+
function runQuery(pgClient, text, values) {
|
|
93
|
+
return pgClient.query(values === undefined ? { text } : { text, values });
|
|
94
|
+
}
|
|
84
95
|
/**
|
|
85
96
|
* Resolve the storage module for a given scope.
|
|
86
97
|
* If ownerId is provided, probes entity tables to find the matching module.
|
|
@@ -89,16 +100,16 @@ const ALL_STORAGE_MODULES_QUERY = `
|
|
|
89
100
|
async function resolveStorageModule(pgClient, databaseId, ownerId) {
|
|
90
101
|
if (!ownerId) {
|
|
91
102
|
// App-level resolution
|
|
92
|
-
const result = await pgClient
|
|
103
|
+
const result = await runQuery(pgClient, APP_STORAGE_MODULE_QUERY, [databaseId]);
|
|
93
104
|
return result.rows[0] ?? null;
|
|
94
105
|
}
|
|
95
106
|
// Entity-scoped: load all modules and probe entity tables
|
|
96
|
-
const result = await pgClient
|
|
107
|
+
const result = await runQuery(pgClient, ALL_STORAGE_MODULES_QUERY, [databaseId]);
|
|
97
108
|
const modules = result.rows;
|
|
98
109
|
const entityModules = modules.filter((m) => m.entity_schema && m.entity_table);
|
|
99
110
|
for (const mod of entityModules) {
|
|
100
111
|
const entityTable = QuoteUtils.quoteQualifiedIdentifier(mod.entity_schema, mod.entity_table);
|
|
101
|
-
const probe = await pgClient
|
|
112
|
+
const probe = await runQuery(pgClient, `SELECT 1 FROM ${entityTable} WHERE id = $1 LIMIT 1`, [ownerId]);
|
|
102
113
|
if (probe.rows.length > 0) {
|
|
103
114
|
return mod;
|
|
104
115
|
}
|
|
@@ -124,7 +135,7 @@ function storedPhysicalName(row) {
|
|
|
124
135
|
* re-provision never clobbers an already-recorded coordinate.
|
|
125
136
|
*/
|
|
126
137
|
async function recordPhysicalName(withPgClient, bucketsTable, bucketId, physicalName) {
|
|
127
|
-
await withPgClient(null, (client) => client
|
|
138
|
+
await withPgClient(null, (client) => runQuery(client, `UPDATE ${bucketsTable} SET physical_name = $1 WHERE id = $2 AND physical_name IS NULL`, [physicalName, bucketId]));
|
|
128
139
|
log.info(`Recorded physical_name="${physicalName}" on bucket ${bucketId}`);
|
|
129
140
|
}
|
|
130
141
|
// --- Helpers ---
|
|
@@ -157,7 +168,7 @@ function resolveBucketName(bucketKey, databaseId, options) {
|
|
|
157
168
|
* Resolve the database_id from the JWT context.
|
|
158
169
|
*/
|
|
159
170
|
async function resolveDatabaseId(pgClient) {
|
|
160
|
-
const result = await pgClient
|
|
171
|
+
const result = await runQuery(pgClient, `SELECT jwt_private.current_database_id() AS id`);
|
|
161
172
|
return result.rows[0]?.id ?? null;
|
|
162
173
|
}
|
|
163
174
|
/**
|
|
@@ -323,7 +334,7 @@ export function createBucketProvisionerPlugin(options) {
|
|
|
323
334
|
// Look up the bucket row (RLS enforced via pgSettings)
|
|
324
335
|
const hasOwner = ownerId && storageModule.scope !== 'app';
|
|
325
336
|
const bucketsTable = QuoteUtils.quoteQualifiedIdentifier(storageModule.buckets_schema, storageModule.buckets_table);
|
|
326
|
-
const bucketResult = await pgClient
|
|
337
|
+
const bucketResult = await runQuery(pgClient, hasOwner
|
|
327
338
|
? `SELECT id, key, type, is_public, allowed_origins, physical_name
|
|
328
339
|
FROM ${bucketsTable}
|
|
329
340
|
WHERE key = $1 AND owner_id = $2
|
|
@@ -451,7 +462,7 @@ export function createBucketProvisionerPlugin(options) {
|
|
|
451
462
|
const storageModule = await resolveStorageModule(pgClient, databaseId);
|
|
452
463
|
if (storageModule) {
|
|
453
464
|
const bucketsTable = QuoteUtils.quoteQualifiedIdentifier(storageModule.buckets_schema, storageModule.buckets_table);
|
|
454
|
-
const idResult = await pgClient
|
|
465
|
+
const idResult = await runQuery(pgClient, `SELECT id FROM ${bucketsTable} WHERE key = $1 LIMIT 1`, [bucketInput.key]);
|
|
455
466
|
const bucketId = idResult.rows[0]?.id;
|
|
456
467
|
if (bucketId)
|
|
457
468
|
await recordPhysicalName(withPgClient, bucketsTable, bucketId, result.bucketName);
|
|
@@ -489,7 +500,7 @@ export function createBucketProvisionerPlugin(options) {
|
|
|
489
500
|
}
|
|
490
501
|
// Read the full bucket row (post-update) to get type + origins
|
|
491
502
|
const bucketsTable = QuoteUtils.quoteQualifiedIdentifier(storageModule.buckets_schema, storageModule.buckets_table);
|
|
492
|
-
const bucketResult = await pgClient
|
|
503
|
+
const bucketResult = await runQuery(pgClient, `SELECT id, key, type, is_public, allowed_origins, physical_name
|
|
493
504
|
FROM ${bucketsTable}
|
|
494
505
|
WHERE key = $1
|
|
495
506
|
LIMIT 1`, [patchKey]);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "graphile-bucket-provisioner-plugin",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.11.0",
|
|
4
4
|
"description": "Bucket provisioning plugin for PostGraphile v5 — auto-provisions S3 buckets on bucket table mutations",
|
|
5
5
|
"author": "Constructive <developers@constructive.io>",
|
|
6
6
|
"homepage": "https://github.com/constructive-io/constructive",
|
|
@@ -57,5 +57,5 @@
|
|
|
57
57
|
"@types/node": "^22.19.11",
|
|
58
58
|
"makage": "^0.3.0"
|
|
59
59
|
},
|
|
60
|
-
"gitHead": "
|
|
60
|
+
"gitHead": "247e48d25b13524d992f00c1b2dc063884d1deb1"
|
|
61
61
|
}
|
package/plugin.js
CHANGED
|
@@ -85,6 +85,17 @@ const ALL_STORAGE_MODULES_QUERY = `
|
|
|
85
85
|
LEFT JOIN metaschema_public.schema es ON es.id = et.schema_id
|
|
86
86
|
WHERE sm.database_id = $1
|
|
87
87
|
`;
|
|
88
|
+
/**
|
|
89
|
+
* Run a query against a grafast `withPgClient` client.
|
|
90
|
+
*
|
|
91
|
+
* That client's `query` takes the `{ text, values }` object form (the same
|
|
92
|
+
* shape the presigned-url plugin uses) — NOT node-pg's positional
|
|
93
|
+
* `(text, params)` args, which surface as "A query must have either text or a
|
|
94
|
+
* name" at runtime.
|
|
95
|
+
*/
|
|
96
|
+
function runQuery(pgClient, text, values) {
|
|
97
|
+
return pgClient.query(values === undefined ? { text } : { text, values });
|
|
98
|
+
}
|
|
88
99
|
/**
|
|
89
100
|
* Resolve the storage module for a given scope.
|
|
90
101
|
* If ownerId is provided, probes entity tables to find the matching module.
|
|
@@ -93,16 +104,16 @@ const ALL_STORAGE_MODULES_QUERY = `
|
|
|
93
104
|
async function resolveStorageModule(pgClient, databaseId, ownerId) {
|
|
94
105
|
if (!ownerId) {
|
|
95
106
|
// App-level resolution
|
|
96
|
-
const result = await pgClient
|
|
107
|
+
const result = await runQuery(pgClient, APP_STORAGE_MODULE_QUERY, [databaseId]);
|
|
97
108
|
return result.rows[0] ?? null;
|
|
98
109
|
}
|
|
99
110
|
// Entity-scoped: load all modules and probe entity tables
|
|
100
|
-
const result = await pgClient
|
|
111
|
+
const result = await runQuery(pgClient, ALL_STORAGE_MODULES_QUERY, [databaseId]);
|
|
101
112
|
const modules = result.rows;
|
|
102
113
|
const entityModules = modules.filter((m) => m.entity_schema && m.entity_table);
|
|
103
114
|
for (const mod of entityModules) {
|
|
104
115
|
const entityTable = quotes_1.QuoteUtils.quoteQualifiedIdentifier(mod.entity_schema, mod.entity_table);
|
|
105
|
-
const probe = await pgClient
|
|
116
|
+
const probe = await runQuery(pgClient, `SELECT 1 FROM ${entityTable} WHERE id = $1 LIMIT 1`, [ownerId]);
|
|
106
117
|
if (probe.rows.length > 0) {
|
|
107
118
|
return mod;
|
|
108
119
|
}
|
|
@@ -128,7 +139,7 @@ function storedPhysicalName(row) {
|
|
|
128
139
|
* re-provision never clobbers an already-recorded coordinate.
|
|
129
140
|
*/
|
|
130
141
|
async function recordPhysicalName(withPgClient, bucketsTable, bucketId, physicalName) {
|
|
131
|
-
await withPgClient(null, (client) => client
|
|
142
|
+
await withPgClient(null, (client) => runQuery(client, `UPDATE ${bucketsTable} SET physical_name = $1 WHERE id = $2 AND physical_name IS NULL`, [physicalName, bucketId]));
|
|
132
143
|
log.info(`Recorded physical_name="${physicalName}" on bucket ${bucketId}`);
|
|
133
144
|
}
|
|
134
145
|
// --- Helpers ---
|
|
@@ -161,7 +172,7 @@ function resolveBucketName(bucketKey, databaseId, options) {
|
|
|
161
172
|
* Resolve the database_id from the JWT context.
|
|
162
173
|
*/
|
|
163
174
|
async function resolveDatabaseId(pgClient) {
|
|
164
|
-
const result = await pgClient
|
|
175
|
+
const result = await runQuery(pgClient, `SELECT jwt_private.current_database_id() AS id`);
|
|
165
176
|
return result.rows[0]?.id ?? null;
|
|
166
177
|
}
|
|
167
178
|
/**
|
|
@@ -327,7 +338,7 @@ function createBucketProvisionerPlugin(options) {
|
|
|
327
338
|
// Look up the bucket row (RLS enforced via pgSettings)
|
|
328
339
|
const hasOwner = ownerId && storageModule.scope !== 'app';
|
|
329
340
|
const bucketsTable = quotes_1.QuoteUtils.quoteQualifiedIdentifier(storageModule.buckets_schema, storageModule.buckets_table);
|
|
330
|
-
const bucketResult = await pgClient
|
|
341
|
+
const bucketResult = await runQuery(pgClient, hasOwner
|
|
331
342
|
? `SELECT id, key, type, is_public, allowed_origins, physical_name
|
|
332
343
|
FROM ${bucketsTable}
|
|
333
344
|
WHERE key = $1 AND owner_id = $2
|
|
@@ -455,7 +466,7 @@ function createBucketProvisionerPlugin(options) {
|
|
|
455
466
|
const storageModule = await resolveStorageModule(pgClient, databaseId);
|
|
456
467
|
if (storageModule) {
|
|
457
468
|
const bucketsTable = quotes_1.QuoteUtils.quoteQualifiedIdentifier(storageModule.buckets_schema, storageModule.buckets_table);
|
|
458
|
-
const idResult = await pgClient
|
|
469
|
+
const idResult = await runQuery(pgClient, `SELECT id FROM ${bucketsTable} WHERE key = $1 LIMIT 1`, [bucketInput.key]);
|
|
459
470
|
const bucketId = idResult.rows[0]?.id;
|
|
460
471
|
if (bucketId)
|
|
461
472
|
await recordPhysicalName(withPgClient, bucketsTable, bucketId, result.bucketName);
|
|
@@ -493,7 +504,7 @@ function createBucketProvisionerPlugin(options) {
|
|
|
493
504
|
}
|
|
494
505
|
// Read the full bucket row (post-update) to get type + origins
|
|
495
506
|
const bucketsTable = quotes_1.QuoteUtils.quoteQualifiedIdentifier(storageModule.buckets_schema, storageModule.buckets_table);
|
|
496
|
-
const bucketResult = await pgClient
|
|
507
|
+
const bucketResult = await runQuery(pgClient, `SELECT id, key, type, is_public, allowed_origins, physical_name
|
|
497
508
|
FROM ${bucketsTable}
|
|
498
509
|
WHERE key = $1
|
|
499
510
|
LIMIT 1`, [patchKey]);
|