graphile-bucket-provisioner-plugin 1.18.1 → 1.19.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/README.md +10 -8
- package/esm/index.d.ts +1 -1
- package/esm/index.js +1 -1
- package/esm/plugin.d.ts +5 -4
- package/esm/plugin.js +30 -26
- package/esm/types.d.ts +4 -4
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/package.json +2 -2
- package/plugin.d.ts +5 -4
- package/plugin.js +30 -26
- package/types.d.ts +4 -4
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ queueing storage reconciliation.
|
|
|
5
5
|
|
|
6
6
|
The constructive-db `storage:provision_bucket` job is the only component that
|
|
7
7
|
mints physical S3 bucket names, provisions S3, and records `physical_name`.
|
|
8
|
-
This plugin resolves the logical bucket under RLS and
|
|
8
|
+
This plugin resolves the logical bucket under RLS and requests that job; it
|
|
9
9
|
does not call S3 or derive a physical name.
|
|
10
10
|
|
|
11
11
|
## Installation
|
|
@@ -32,16 +32,18 @@ mutation {
|
|
|
32
32
|
bucketId
|
|
33
33
|
bucketKey
|
|
34
34
|
physicalName
|
|
35
|
-
|
|
35
|
+
provisionRequestedAt
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
-
`provisionBucket` resolves the bucket row under RLS and
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
`provisionBucket` resolves the bucket row under RLS and calls the storage
|
|
41
|
+
module's `<buckets>_provision(bucket_id)`, which stamps the row's
|
|
42
|
+
`provision_requested_at` as the caller and returns the row. The bucket's UPDATE
|
|
43
|
+
job trigger then enqueues the same `storage:provision_bucket` job used on
|
|
44
|
+
INSERT, keyed `storage:provision_bucket:<uuid>` on the `bucket:<uuid>` queue, so
|
|
45
|
+
repeated requests while a job is waiting collapse into it. Failures are
|
|
46
|
+
returned as GraphQL errors.
|
|
45
47
|
|
|
46
48
|
The payload fields are:
|
|
47
49
|
|
|
@@ -50,7 +52,7 @@ The payload fields are:
|
|
|
50
52
|
| `bucketId` | Logical bucket row ID |
|
|
51
53
|
| `bucketKey` | Logical bucket key |
|
|
52
54
|
| `physicalName` | Recorded physical name, or `null` while reconciliation is pending |
|
|
53
|
-
| `
|
|
55
|
+
| `provisionRequestedAt` | When reconciliation was last requested |
|
|
54
56
|
|
|
55
57
|
There are no plugin options: S3 connection details, naming, CORS, versioning,
|
|
56
58
|
and physical-name recording belong to the reconciler.
|
package/esm/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Bucket Provisioner Plugin for PostGraphile v5
|
|
3
3
|
*
|
|
4
|
-
* Provides an explicit `provisionBucket` reconciliation
|
|
4
|
+
* Provides an explicit `provisionBucket` reconciliation request mutation for
|
|
5
5
|
* PostGraphile v5.
|
|
6
6
|
*/
|
|
7
7
|
export { BucketProvisionerPlugin, createBucketProvisionerPlugin } from './plugin';
|
package/esm/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Bucket Provisioner Plugin for PostGraphile v5
|
|
3
3
|
*
|
|
4
|
-
* Provides an explicit `provisionBucket` reconciliation
|
|
4
|
+
* Provides an explicit `provisionBucket` reconciliation request mutation for
|
|
5
5
|
* PostGraphile v5.
|
|
6
6
|
*/
|
|
7
7
|
export { BucketProvisionerPlugin, createBucketProvisionerPlugin } from './plugin';
|
package/esm/plugin.d.ts
CHANGED
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Adds S3 bucket provisioning support to PostGraphile v5:
|
|
5
5
|
*
|
|
6
|
-
* 1. `provisionBucket` mutation — explicitly
|
|
7
|
-
* logical bucket row in the database.
|
|
8
|
-
*
|
|
6
|
+
* 1. `provisionBucket` mutation — explicitly request reconciliation for a
|
|
7
|
+
* logical bucket row in the database. Stamps the bucket's
|
|
8
|
+
* `provision_requested_at` via RLS; the bucket's own job trigger then
|
|
9
|
+
* queues the same storage reconciler job used on INSERT.
|
|
9
10
|
*
|
|
10
11
|
* Detection: Uses the `@storageBuckets` smart tag on the codec (table).
|
|
11
12
|
* The storage module generator in constructive-db sets this tag on the
|
|
@@ -19,7 +20,7 @@ import type { GraphileConfig } from 'graphile-config';
|
|
|
19
20
|
* This plugin provides one reconciliation pathway:
|
|
20
21
|
*
|
|
21
22
|
* 1. **Explicit `provisionBucket` mutation** — Call this mutation with a
|
|
22
|
-
* bucket key to
|
|
23
|
+
* bucket key to request reconciliation (or re-reconciliation) for the
|
|
23
24
|
* bucket. Protected by RLS on the buckets table.
|
|
24
25
|
*
|
|
25
26
|
*/
|
package/esm/plugin.js
CHANGED
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Adds S3 bucket provisioning support to PostGraphile v5:
|
|
5
5
|
*
|
|
6
|
-
* 1. `provisionBucket` mutation — explicitly
|
|
7
|
-
* logical bucket row in the database.
|
|
8
|
-
*
|
|
6
|
+
* 1. `provisionBucket` mutation — explicitly request reconciliation for a
|
|
7
|
+
* logical bucket row in the database. Stamps the bucket's
|
|
8
|
+
* `provision_requested_at` via RLS; the bucket's own job trigger then
|
|
9
|
+
* queues the same storage reconciler job used on INSERT.
|
|
9
10
|
*
|
|
10
11
|
* Detection: Uses the `@storageBuckets` smart tag on the codec (table).
|
|
11
12
|
* The storage module generator in constructive-db sets this tag on the
|
|
@@ -108,19 +109,21 @@ async function resolveDatabaseId(pgClient) {
|
|
|
108
109
|
return result.rows[0]?.id ?? null;
|
|
109
110
|
}
|
|
110
111
|
/**
|
|
111
|
-
*
|
|
112
|
-
* `<private>.<buckets>_provision(bucket_id)`. It runs as the request role
|
|
113
|
-
*
|
|
114
|
-
*
|
|
112
|
+
* Request reconciliation through the storage module's generated
|
|
113
|
+
* `<private>.<buckets>_provision(bucket_id)`. It runs as the request role and
|
|
114
|
+
* stamps the bucket's `provision_requested_at` under the buckets table's own
|
|
115
|
+
* RLS; the bucket's UPDATE job trigger then enqueues the reconciler (keyed and
|
|
116
|
+
* queued on the bucket, so repeated requests collapse into one pending job).
|
|
117
|
+
* It returns the updated bucket row.
|
|
115
118
|
*/
|
|
116
|
-
async function
|
|
119
|
+
async function requestReconciliation(pgClient, storageModule, bucket) {
|
|
117
120
|
const provisionFunction = QuoteUtils.quoteQualifiedIdentifier(storageModule.private_schema, `${storageModule.buckets_table}_provision`);
|
|
118
|
-
const result = await runQuery(pgClient, `SELECT ${provisionFunction}($1::uuid)
|
|
119
|
-
const
|
|
120
|
-
if (!
|
|
121
|
-
throw new Error(`
|
|
121
|
+
const result = await runQuery(pgClient, `SELECT id, key, physical_name, to_json(provision_requested_at) #>> '{}' AS provision_requested_at FROM ${provisionFunction}($1::uuid)`, [bucket.id]);
|
|
122
|
+
const row = result.rows[0];
|
|
123
|
+
if (!row?.id) {
|
|
124
|
+
throw new Error(`STORAGE_BUCKET_PROVISION_EMPTY: bucket ${bucket.id}`);
|
|
122
125
|
}
|
|
123
|
-
return
|
|
126
|
+
return row;
|
|
124
127
|
}
|
|
125
128
|
// --- Plugin factory ---
|
|
126
129
|
/**
|
|
@@ -129,7 +132,7 @@ async function enqueueReconciliationJob(pgClient, storageModule, bucket) {
|
|
|
129
132
|
* This plugin provides one reconciliation pathway:
|
|
130
133
|
*
|
|
131
134
|
* 1. **Explicit `provisionBucket` mutation** — Call this mutation with a
|
|
132
|
-
* bucket key to
|
|
135
|
+
* bucket key to request reconciliation (or re-reconciliation) for the
|
|
133
136
|
* bucket. Protected by RLS on the buckets table.
|
|
134
137
|
*
|
|
135
138
|
*/
|
|
@@ -148,22 +151,23 @@ export function createBucketProvisionerPlugin() {
|
|
|
148
151
|
}
|
|
149
152
|
|
|
150
153
|
type ProvisionBucketPayload {
|
|
151
|
-
"""The logical bucket row
|
|
154
|
+
"""The logical bucket row whose reconciliation was requested."""
|
|
152
155
|
bucketId: UUID!
|
|
153
156
|
bucketKey: String!
|
|
154
157
|
"""The physical bucket name already recorded, or null when reconciliation has not completed."""
|
|
155
158
|
physicalName: String
|
|
156
|
-
"""
|
|
157
|
-
|
|
159
|
+
"""When reconciliation was last requested for this bucket."""
|
|
160
|
+
provisionRequestedAt: Datetime!
|
|
158
161
|
}
|
|
159
162
|
|
|
160
163
|
extend type Mutation {
|
|
161
164
|
"""
|
|
162
165
|
Reconcile an S3 bucket for a logical bucket in the database.
|
|
163
|
-
|
|
164
|
-
storage:provision_bucket job used
|
|
165
|
-
|
|
166
|
-
GraphQL
|
|
166
|
+
Records the request on the bucket row via RLS; the bucket's job
|
|
167
|
+
trigger then enqueues the same storage:provision_bucket job used on
|
|
168
|
+
INSERT, and repeated requests collapse into one pending job. This is
|
|
169
|
+
idempotent for an already-reconciled bucket; failures become GraphQL
|
|
170
|
+
errors.
|
|
167
171
|
"""
|
|
168
172
|
provisionBucket(
|
|
169
173
|
input: ProvisionBucketInput!
|
|
@@ -199,12 +203,12 @@ export function createBucketProvisionerPlugin() {
|
|
|
199
203
|
throw new Error('BUCKET_NOT_FOUND');
|
|
200
204
|
}
|
|
201
205
|
const { storageModule, bucket } = resolution;
|
|
202
|
-
const
|
|
206
|
+
const provisioned = await requestReconciliation(pgClient, storageModule, bucket);
|
|
203
207
|
return {
|
|
204
|
-
bucketId:
|
|
205
|
-
bucketKey:
|
|
206
|
-
physicalName:
|
|
207
|
-
|
|
208
|
+
bucketId: provisioned.id,
|
|
209
|
+
bucketKey: provisioned.key,
|
|
210
|
+
physicalName: provisioned.physical_name,
|
|
211
|
+
provisionRequestedAt: provisioned.provision_requested_at,
|
|
208
212
|
};
|
|
209
213
|
});
|
|
210
214
|
});
|
package/esm/types.d.ts
CHANGED
|
@@ -14,15 +14,15 @@ export interface ProvisionBucketInput {
|
|
|
14
14
|
ownerId?: string;
|
|
15
15
|
}
|
|
16
16
|
/**
|
|
17
|
-
* Result of the provisionBucket
|
|
17
|
+
* Result of the provisionBucket mutation: the bucket row it stamped.
|
|
18
18
|
*/
|
|
19
19
|
export interface ProvisionBucketPayload {
|
|
20
|
-
/** The logical bucket row
|
|
20
|
+
/** The logical bucket row whose reconciliation was requested */
|
|
21
21
|
bucketId: string;
|
|
22
22
|
/** The logical bucket key */
|
|
23
23
|
bucketKey: string;
|
|
24
24
|
/** The physical name already recorded, or null while reconciliation is pending */
|
|
25
25
|
physicalName: string | null;
|
|
26
|
-
/**
|
|
27
|
-
|
|
26
|
+
/** When reconciliation was last requested */
|
|
27
|
+
provisionRequestedAt: string;
|
|
28
28
|
}
|
package/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Bucket Provisioner Plugin for PostGraphile v5
|
|
3
3
|
*
|
|
4
|
-
* Provides an explicit `provisionBucket` reconciliation
|
|
4
|
+
* Provides an explicit `provisionBucket` reconciliation request mutation for
|
|
5
5
|
* PostGraphile v5.
|
|
6
6
|
*/
|
|
7
7
|
export { BucketProvisionerPlugin, createBucketProvisionerPlugin } from './plugin';
|
package/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Bucket Provisioner Plugin for PostGraphile v5
|
|
4
4
|
*
|
|
5
|
-
* Provides an explicit `provisionBucket` reconciliation
|
|
5
|
+
* Provides an explicit `provisionBucket` reconciliation request mutation for
|
|
6
6
|
* PostGraphile v5.
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "graphile-bucket-provisioner-plugin",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.19.0",
|
|
4
4
|
"description": "Bucket provisioning plugin for PostGraphile v5 — explicitly provisions S3 buckets via a GraphQL mutation",
|
|
5
5
|
"author": "Constructive <developers@constructive.io>",
|
|
6
6
|
"homepage": "https://github.com/constructive-io/constructive",
|
|
@@ -58,5 +58,5 @@
|
|
|
58
58
|
"@types/node": "^22.19.11",
|
|
59
59
|
"makage": "^0.8.0"
|
|
60
60
|
},
|
|
61
|
-
"gitHead": "
|
|
61
|
+
"gitHead": "b6c80da2ba0532a4aaf0d0154901efa7911974d8"
|
|
62
62
|
}
|
package/plugin.d.ts
CHANGED
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Adds S3 bucket provisioning support to PostGraphile v5:
|
|
5
5
|
*
|
|
6
|
-
* 1. `provisionBucket` mutation — explicitly
|
|
7
|
-
* logical bucket row in the database.
|
|
8
|
-
*
|
|
6
|
+
* 1. `provisionBucket` mutation — explicitly request reconciliation for a
|
|
7
|
+
* logical bucket row in the database. Stamps the bucket's
|
|
8
|
+
* `provision_requested_at` via RLS; the bucket's own job trigger then
|
|
9
|
+
* queues the same storage reconciler job used on INSERT.
|
|
9
10
|
*
|
|
10
11
|
* Detection: Uses the `@storageBuckets` smart tag on the codec (table).
|
|
11
12
|
* The storage module generator in constructive-db sets this tag on the
|
|
@@ -19,7 +20,7 @@ import type { GraphileConfig } from 'graphile-config';
|
|
|
19
20
|
* This plugin provides one reconciliation pathway:
|
|
20
21
|
*
|
|
21
22
|
* 1. **Explicit `provisionBucket` mutation** — Call this mutation with a
|
|
22
|
-
* bucket key to
|
|
23
|
+
* bucket key to request reconciliation (or re-reconciliation) for the
|
|
23
24
|
* bucket. Protected by RLS on the buckets table.
|
|
24
25
|
*
|
|
25
26
|
*/
|
package/plugin.js
CHANGED
|
@@ -4,9 +4,10 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Adds S3 bucket provisioning support to PostGraphile v5:
|
|
6
6
|
*
|
|
7
|
-
* 1. `provisionBucket` mutation — explicitly
|
|
8
|
-
* logical bucket row in the database.
|
|
9
|
-
*
|
|
7
|
+
* 1. `provisionBucket` mutation — explicitly request reconciliation for a
|
|
8
|
+
* logical bucket row in the database. Stamps the bucket's
|
|
9
|
+
* `provision_requested_at` via RLS; the bucket's own job trigger then
|
|
10
|
+
* queues the same storage reconciler job used on INSERT.
|
|
10
11
|
*
|
|
11
12
|
* Detection: Uses the `@storageBuckets` smart tag on the codec (table).
|
|
12
13
|
* The storage module generator in constructive-db sets this tag on the
|
|
@@ -112,19 +113,21 @@ async function resolveDatabaseId(pgClient) {
|
|
|
112
113
|
return result.rows[0]?.id ?? null;
|
|
113
114
|
}
|
|
114
115
|
/**
|
|
115
|
-
*
|
|
116
|
-
* `<private>.<buckets>_provision(bucket_id)`. It runs as the request role
|
|
117
|
-
*
|
|
118
|
-
*
|
|
116
|
+
* Request reconciliation through the storage module's generated
|
|
117
|
+
* `<private>.<buckets>_provision(bucket_id)`. It runs as the request role and
|
|
118
|
+
* stamps the bucket's `provision_requested_at` under the buckets table's own
|
|
119
|
+
* RLS; the bucket's UPDATE job trigger then enqueues the reconciler (keyed and
|
|
120
|
+
* queued on the bucket, so repeated requests collapse into one pending job).
|
|
121
|
+
* It returns the updated bucket row.
|
|
119
122
|
*/
|
|
120
|
-
async function
|
|
123
|
+
async function requestReconciliation(pgClient, storageModule, bucket) {
|
|
121
124
|
const provisionFunction = quotes_1.QuoteUtils.quoteQualifiedIdentifier(storageModule.private_schema, `${storageModule.buckets_table}_provision`);
|
|
122
|
-
const result = await runQuery(pgClient, `SELECT ${provisionFunction}($1::uuid)
|
|
123
|
-
const
|
|
124
|
-
if (!
|
|
125
|
-
throw new Error(`
|
|
125
|
+
const result = await runQuery(pgClient, `SELECT id, key, physical_name, to_json(provision_requested_at) #>> '{}' AS provision_requested_at FROM ${provisionFunction}($1::uuid)`, [bucket.id]);
|
|
126
|
+
const row = result.rows[0];
|
|
127
|
+
if (!row?.id) {
|
|
128
|
+
throw new Error(`STORAGE_BUCKET_PROVISION_EMPTY: bucket ${bucket.id}`);
|
|
126
129
|
}
|
|
127
|
-
return
|
|
130
|
+
return row;
|
|
128
131
|
}
|
|
129
132
|
// --- Plugin factory ---
|
|
130
133
|
/**
|
|
@@ -133,7 +136,7 @@ async function enqueueReconciliationJob(pgClient, storageModule, bucket) {
|
|
|
133
136
|
* This plugin provides one reconciliation pathway:
|
|
134
137
|
*
|
|
135
138
|
* 1. **Explicit `provisionBucket` mutation** — Call this mutation with a
|
|
136
|
-
* bucket key to
|
|
139
|
+
* bucket key to request reconciliation (or re-reconciliation) for the
|
|
137
140
|
* bucket. Protected by RLS on the buckets table.
|
|
138
141
|
*
|
|
139
142
|
*/
|
|
@@ -152,22 +155,23 @@ function createBucketProvisionerPlugin() {
|
|
|
152
155
|
}
|
|
153
156
|
|
|
154
157
|
type ProvisionBucketPayload {
|
|
155
|
-
"""The logical bucket row
|
|
158
|
+
"""The logical bucket row whose reconciliation was requested."""
|
|
156
159
|
bucketId: UUID!
|
|
157
160
|
bucketKey: String!
|
|
158
161
|
"""The physical bucket name already recorded, or null when reconciliation has not completed."""
|
|
159
162
|
physicalName: String
|
|
160
|
-
"""
|
|
161
|
-
|
|
163
|
+
"""When reconciliation was last requested for this bucket."""
|
|
164
|
+
provisionRequestedAt: Datetime!
|
|
162
165
|
}
|
|
163
166
|
|
|
164
167
|
extend type Mutation {
|
|
165
168
|
"""
|
|
166
169
|
Reconcile an S3 bucket for a logical bucket in the database.
|
|
167
|
-
|
|
168
|
-
storage:provision_bucket job used
|
|
169
|
-
|
|
170
|
-
GraphQL
|
|
170
|
+
Records the request on the bucket row via RLS; the bucket's job
|
|
171
|
+
trigger then enqueues the same storage:provision_bucket job used on
|
|
172
|
+
INSERT, and repeated requests collapse into one pending job. This is
|
|
173
|
+
idempotent for an already-reconciled bucket; failures become GraphQL
|
|
174
|
+
errors.
|
|
171
175
|
"""
|
|
172
176
|
provisionBucket(
|
|
173
177
|
input: ProvisionBucketInput!
|
|
@@ -203,12 +207,12 @@ function createBucketProvisionerPlugin() {
|
|
|
203
207
|
throw new Error('BUCKET_NOT_FOUND');
|
|
204
208
|
}
|
|
205
209
|
const { storageModule, bucket } = resolution;
|
|
206
|
-
const
|
|
210
|
+
const provisioned = await requestReconciliation(pgClient, storageModule, bucket);
|
|
207
211
|
return {
|
|
208
|
-
bucketId:
|
|
209
|
-
bucketKey:
|
|
210
|
-
physicalName:
|
|
211
|
-
|
|
212
|
+
bucketId: provisioned.id,
|
|
213
|
+
bucketKey: provisioned.key,
|
|
214
|
+
physicalName: provisioned.physical_name,
|
|
215
|
+
provisionRequestedAt: provisioned.provision_requested_at,
|
|
212
216
|
};
|
|
213
217
|
});
|
|
214
218
|
});
|
package/types.d.ts
CHANGED
|
@@ -14,15 +14,15 @@ export interface ProvisionBucketInput {
|
|
|
14
14
|
ownerId?: string;
|
|
15
15
|
}
|
|
16
16
|
/**
|
|
17
|
-
* Result of the provisionBucket
|
|
17
|
+
* Result of the provisionBucket mutation: the bucket row it stamped.
|
|
18
18
|
*/
|
|
19
19
|
export interface ProvisionBucketPayload {
|
|
20
|
-
/** The logical bucket row
|
|
20
|
+
/** The logical bucket row whose reconciliation was requested */
|
|
21
21
|
bucketId: string;
|
|
22
22
|
/** The logical bucket key */
|
|
23
23
|
bucketKey: string;
|
|
24
24
|
/** The physical name already recorded, or null while reconciliation is pending */
|
|
25
25
|
physicalName: string | null;
|
|
26
|
-
/**
|
|
27
|
-
|
|
26
|
+
/** When reconciliation was last requested */
|
|
27
|
+
provisionRequestedAt: string;
|
|
28
28
|
}
|