graphile-bucket-provisioner-plugin 1.10.0 → 1.12.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.
Files changed (3) hide show
  1. package/esm/plugin.js +19 -8
  2. package/package.json +4 -4
  3. 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.query(APP_STORAGE_MODULE_QUERY, [databaseId]);
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.query(ALL_STORAGE_MODULES_QUERY, [databaseId]);
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.query(`SELECT 1 FROM ${entityTable} WHERE id = $1 LIMIT 1`, [ownerId]);
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.query(`UPDATE ${bucketsTable} SET physical_name = $1 WHERE id = $2 AND physical_name IS NULL`, [physicalName, bucketId]));
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.query(`SELECT jwt_private.current_database_id() AS id`);
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.query(hasOwner
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.query(`SELECT id FROM ${bucketsTable} WHERE key = $1 LIMIT 1`, [bucketInput.key]);
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.query(`SELECT id, key, type, is_public, allowed_origins, physical_name
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.10.0",
3
+ "version": "1.12.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",
@@ -40,8 +40,8 @@
40
40
  "url": "https://github.com/constructive-io/constructive/issues"
41
41
  },
42
42
  "dependencies": {
43
- "@constructive-io/bucket-provisioner": "^0.23.3",
44
- "@pgpmjs/logger": "^2.23.3",
43
+ "@constructive-io/bucket-provisioner": "^0.24.0",
44
+ "@pgpmjs/logger": "^2.24.0",
45
45
  "@pgsql/quotes": "^18.2.0"
46
46
  },
47
47
  "peerDependencies": {
@@ -57,5 +57,5 @@
57
57
  "@types/node": "^22.19.11",
58
58
  "makage": "^0.3.0"
59
59
  },
60
- "gitHead": "c438821362ceaf70b2a20d74ecf25ad4191c1748"
60
+ "gitHead": "d508453a32a2f1d70ff6916871046615226e6f33"
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.query(APP_STORAGE_MODULE_QUERY, [databaseId]);
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.query(ALL_STORAGE_MODULES_QUERY, [databaseId]);
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.query(`SELECT 1 FROM ${entityTable} WHERE id = $1 LIMIT 1`, [ownerId]);
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.query(`UPDATE ${bucketsTable} SET physical_name = $1 WHERE id = $2 AND physical_name IS NULL`, [physicalName, bucketId]));
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.query(`SELECT jwt_private.current_database_id() AS id`);
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.query(hasOwner
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.query(`SELECT id FROM ${bucketsTable} WHERE key = $1 LIMIT 1`, [bucketInput.key]);
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.query(`SELECT id, key, type, is_public, allowed_origins, physical_name
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]);