@pellux/goodvibes-sdk 0.25.14 → 0.25.15
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/dist/_internal/contracts/artifacts/operator-contract.json +1 -1
- package/dist/_internal/contracts/generated/foundation-metadata.d.ts +1 -1
- package/dist/_internal/contracts/generated/foundation-metadata.js +1 -1
- package/dist/_internal/contracts/generated/operator-contract.js +1 -1
- package/dist/_internal/platform/cloudflare/manager.d.ts +1 -1
- package/dist/_internal/platform/cloudflare/manager.d.ts.map +1 -1
- package/dist/_internal/platform/cloudflare/manager.js +4 -5
- package/dist/_internal/platform/cloudflare/utils.d.ts +4 -0
- package/dist/_internal/platform/cloudflare/utils.d.ts.map +1 -1
- package/dist/_internal/platform/cloudflare/utils.js +72 -2
- package/dist/_internal/platform/version.js +1 -1
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Synced from packages/contracts/src/generated/foundation-metadata.ts
|
|
2
2
|
export const FOUNDATION_METADATA = {
|
|
3
3
|
"productId": "goodvibes",
|
|
4
|
-
"productVersion": "0.25.
|
|
4
|
+
"productVersion": "0.25.15",
|
|
5
5
|
"operatorMethodCount": 224,
|
|
6
6
|
"operatorEventCount": 30,
|
|
7
7
|
"peerEndpointCount": 6
|
|
@@ -21,7 +21,7 @@ export declare class CloudflareControlPlaneManager {
|
|
|
21
21
|
private resolveSecretRef;
|
|
22
22
|
private storeSecret;
|
|
23
23
|
private requireUserTokens;
|
|
24
|
-
private
|
|
24
|
+
private resolvePermissionGroupIds;
|
|
25
25
|
private createProvisioningContext;
|
|
26
26
|
private fetchWorker;
|
|
27
27
|
private generateToken;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../../../src/_internal/platform/cloudflare/manager.ts"],"names":[],"mappings":"AAuCA,OAAO,KAAK,EAIV,6BAA6B,EAC7B,4BAA4B,EAC5B,uBAAuB,EACvB,wBAAwB,EACxB,sBAAsB,EACtB,uBAAuB,EAGvB,+BAA+B,EAC/B,gCAAgC,
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../../../src/_internal/platform/cloudflare/manager.ts"],"names":[],"mappings":"AAuCA,OAAO,KAAK,EAIV,6BAA6B,EAC7B,4BAA4B,EAC5B,uBAAuB,EACvB,wBAAwB,EACxB,sBAAsB,EACtB,uBAAuB,EAGvB,+BAA+B,EAC/B,gCAAgC,EAChC,wBAAwB,EACxB,yBAAyB,EAOzB,gCAAgC,EAChC,iCAAiC,EAEjC,uBAAuB,EACvB,wBAAwB,EACxB,qBAAqB,EACrB,sBAAsB,EACvB,MAAM,YAAY,CAAC;AAiBpB,qBAAa,6BAA6B;IAI5B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAHpC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAqD;IAClF,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;gBAEZ,OAAO,EAAE,6BAA6B;IAK7D,cAAc,IAAI,OAAO,CAAC,4BAA4B,CAAC;IA0C7D,iBAAiB,CAAC,KAAK,GAAE,gCAAqC,GAAG,iCAAiC;IAkB5F,sBAAsB,CAAC,KAAK,EAAE,+BAA+B,GAAG,OAAO,CAAC,gCAAgC,CAAC;IAyEzG,QAAQ,CAAC,KAAK,GAAE,uBAA4B,GAAG,OAAO,CAAC,wBAAwB,CAAC;IAuEhF,QAAQ,CAAC,KAAK,EAAE,uBAAuB,GAAG,OAAO,CAAC,wBAAwB,CAAC;IAuB3E,SAAS,CAAC,KAAK,EAAE,wBAAwB,GAAG,OAAO,CAAC,yBAAyB,CAAC;IA2S9E,MAAM,CAAC,KAAK,GAAE,qBAA0B,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAe1E,OAAO,CAAC,KAAK,GAAE,sBAA2B,GAAG,OAAO,CAAC,uBAAuB,CAAC;IA0BnF,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,gBAAgB;IAYxB,OAAO,CAAC,iBAAiB;YAYX,eAAe;YAaf,oBAAoB;YAapB,wBAAwB;YAaxB,gBAAgB;YAahB,WAAW;IAOzB,OAAO,CAAC,iBAAiB;YAOX,yBAAyB;IAQvC,OAAO,CAAC,yBAAyB;YAQnB,WAAW;IAazB,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,SAAS;CAMlB"}
|
|
@@ -6,7 +6,7 @@ import { CLOUDFLARE_API_TOKEN_KEY, CLOUDFLARE_WORKER_CLIENT_TOKEN_KEY, CLOUDFLAR
|
|
|
6
6
|
import { discoverZones, resolveZone, selectDiscoveredZone, tryDiscover, } from './discovery.js';
|
|
7
7
|
import { configureDns, configureWorkerSubdomain, ensureAccess, ensureKvNamespace, ensureQueue, ensureQueueConsumer, ensureR2Bucket, ensureSecretsStore, ensureTunnel, findDurableObjectNamespace, uploadWorker, } from './resources.js';
|
|
8
8
|
import { CloudflareControlPlaneError } from './types.js';
|
|
9
|
-
import { buildTokenRequirements, buildTokenResources, clean, collectAsync, collectSingleAccount, hostnameFromUrl, requireKvNamespaceId, requireQueueId, resolveComponents,
|
|
9
|
+
import { buildTokenRequirements, buildTokenResources, clean, collectAsync, collectSingleAccount, hostnameFromUrl, requireKvNamespaceId, requireQueueId, resolveComponents, resolvePermissionGroupIds, safeResponseText, stripTrailingSlash, } from './utils.js';
|
|
10
10
|
export class CloudflareControlPlaneManager {
|
|
11
11
|
options;
|
|
12
12
|
createClient;
|
|
@@ -105,8 +105,7 @@ export class CloudflareControlPlaneManager {
|
|
|
105
105
|
required: components.dns,
|
|
106
106
|
});
|
|
107
107
|
}
|
|
108
|
-
const
|
|
109
|
-
const permissionIds = selectPermissionGroups(requirements, groups);
|
|
108
|
+
const permissionIds = await this.resolvePermissionGroupIds(client, requirements);
|
|
110
109
|
const resources = buildTokenResources(accountId, zone?.id, components);
|
|
111
110
|
const tokenName = clean(input.tokenName) || 'GoodVibes Cloudflare Operational';
|
|
112
111
|
const token = await this.requireUserTokens(client).create({
|
|
@@ -636,9 +635,9 @@ export class CloudflareControlPlaneManager {
|
|
|
636
635
|
}
|
|
637
636
|
return client.user.tokens;
|
|
638
637
|
}
|
|
639
|
-
async
|
|
638
|
+
async resolvePermissionGroupIds(client, requirements) {
|
|
640
639
|
const tokenApi = this.requireUserTokens(client);
|
|
641
|
-
return await
|
|
640
|
+
return await resolvePermissionGroupIds(requirements, (params) => tokenApi.permissionGroups.list(params));
|
|
642
641
|
}
|
|
643
642
|
createProvisioningContext() {
|
|
644
643
|
return {
|
|
@@ -2,6 +2,10 @@ import type { CloudflareAccountLike, CloudflareApiClient, CloudflareComponent, C
|
|
|
2
2
|
export declare function resolveComponents(selection: CloudflareComponentSelection | undefined): Readonly<Record<CloudflareComponent, boolean>>;
|
|
3
3
|
export declare function buildTokenRequirements(components: Readonly<Record<CloudflareComponent, boolean>>, includeBootstrap: boolean): readonly CloudflareTokenPermissionRequirement[];
|
|
4
4
|
export declare function selectPermissionGroups(requirements: readonly CloudflareTokenPermissionRequirement[], groups: readonly CloudflarePermissionGroupLike[]): readonly string[];
|
|
5
|
+
export declare function resolvePermissionGroupIds(requirements: readonly CloudflareTokenPermissionRequirement[], listPermissionGroups: (params?: {
|
|
6
|
+
readonly name?: string;
|
|
7
|
+
readonly scope?: string;
|
|
8
|
+
}) => AsyncIterable<CloudflarePermissionGroupLike>): Promise<readonly string[]>;
|
|
5
9
|
export declare function buildTokenResources(accountId: string, zoneId: string | undefined, components: Readonly<Record<CloudflareComponent, boolean>>): Record<string, string>;
|
|
6
10
|
export declare function collectSingleAccount(client: CloudflareApiClient, accountId: string, warnings: string[]): Promise<readonly CloudflareAccountLike[]>;
|
|
7
11
|
export declare function collectAsync<T>(iterable: AsyncIterable<T>, limit?: number): Promise<readonly T[]>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../src/_internal/platform/cloudflare/utils.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,qBAAqB,EACrB,mBAAmB,EACnB,mBAAmB,EACnB,4BAA4B,EAC5B,yBAAyB,EACzB,6BAA6B,EAC7B,mBAAmB,EACnB,oCAAoC,EACrC,MAAM,YAAY,CAAC;AAGpB,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,4BAA4B,GAAG,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,mBAAmB,EAAE,OAAO,CAAC,CAAC,CAKrI;AAED,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,mBAAmB,EAAE,OAAO,CAAC,CAAC,EAC1D,gBAAgB,EAAE,OAAO,GACxB,SAAS,oCAAoC,EAAE,CAiHjD;AAED,wBAAgB,sBAAsB,CACpC,YAAY,EAAE,SAAS,oCAAoC,EAAE,EAC7D,MAAM,EAAE,SAAS,6BAA6B,EAAE,GAC/C,SAAS,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../src/_internal/platform/cloudflare/utils.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,qBAAqB,EACrB,mBAAmB,EACnB,mBAAmB,EACnB,4BAA4B,EAC5B,yBAAyB,EACzB,6BAA6B,EAC7B,mBAAmB,EACnB,oCAAoC,EACrC,MAAM,YAAY,CAAC;AAGpB,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,4BAA4B,GAAG,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,mBAAmB,EAAE,OAAO,CAAC,CAAC,CAKrI;AAED,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,mBAAmB,EAAE,OAAO,CAAC,CAAC,EAC1D,gBAAgB,EAAE,OAAO,GACxB,SAAS,oCAAoC,EAAE,CAiHjD;AAED,wBAAgB,sBAAsB,CACpC,YAAY,EAAE,SAAS,oCAAoC,EAAE,EAC7D,MAAM,EAAE,SAAS,6BAA6B,EAAE,GAC/C,SAAS,MAAM,EAAE,CAmBnB;AAED,wBAAsB,yBAAyB,CAC7C,YAAY,EAAE,SAAS,oCAAoC,EAAE,EAC7D,oBAAoB,EAAE,CAAC,MAAM,CAAC,EAAE;IAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,KAAK,aAAa,CAAC,6BAA6B,CAAC,GACnI,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CAqD5B;AAED,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,mBAAmB,EAAE,OAAO,CAAC,CAAC,GACzD,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAWxB;AAED,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,mBAAmB,EAC3B,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAAE,GACjB,OAAO,CAAC,SAAS,qBAAqB,EAAE,CAAC,CAW3C;AAED,wBAAsB,YAAY,CAAC,CAAC,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,KAAK,SAAM,GAAG,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,CAOpG;AAED,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAEvD;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAExD;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAOrD;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAGpF;AAED,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,yBAAyB,GAAG,MAAM,CAGjF;AAED,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAM1E"}
|
|
@@ -117,8 +117,7 @@ export function selectPermissionGroups(requirements, groups) {
|
|
|
117
117
|
const ids = [];
|
|
118
118
|
const missing = [];
|
|
119
119
|
for (const requirement of requirements) {
|
|
120
|
-
const
|
|
121
|
-
const group = groups.find((entry) => entry.id && entry.name && names.some((name) => normalizePermissionName(entry.name) === normalizePermissionName(name)));
|
|
120
|
+
const group = findPermissionGroup(requirement, groups);
|
|
122
121
|
if (group?.id) {
|
|
123
122
|
ids.push(group.id);
|
|
124
123
|
}
|
|
@@ -131,6 +130,54 @@ export function selectPermissionGroups(requirements, groups) {
|
|
|
131
130
|
}
|
|
132
131
|
return Array.from(new Set(ids));
|
|
133
132
|
}
|
|
133
|
+
export async function resolvePermissionGroupIds(requirements, listPermissionGroups) {
|
|
134
|
+
const ids = [];
|
|
135
|
+
const missing = [];
|
|
136
|
+
let scannedGroups = null;
|
|
137
|
+
let lastError;
|
|
138
|
+
const scanAllGroups = async () => {
|
|
139
|
+
if (scannedGroups)
|
|
140
|
+
return scannedGroups;
|
|
141
|
+
scannedGroups = await collectAsync(listPermissionGroups(), 5_000);
|
|
142
|
+
return scannedGroups;
|
|
143
|
+
};
|
|
144
|
+
for (const requirement of requirements) {
|
|
145
|
+
const scope = cloudflareScopeForRequirement(requirement);
|
|
146
|
+
const names = [requirement.permission, ...(requirement.alternatives ?? [])];
|
|
147
|
+
let group;
|
|
148
|
+
for (const name of names) {
|
|
149
|
+
try {
|
|
150
|
+
const exactMatches = await collectAsync(listPermissionGroups({ name, scope }), 50);
|
|
151
|
+
group = findPermissionGroup(requirement, exactMatches);
|
|
152
|
+
if (group)
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
lastError = error;
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (!group) {
|
|
161
|
+
try {
|
|
162
|
+
group = findPermissionGroup(requirement, await scanAllGroups());
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
lastError = error;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
if (group?.id) {
|
|
169
|
+
ids.push(group.id);
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
missing.push(`${requirement.permission} (${requirement.component})`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
if (missing.length > 0) {
|
|
176
|
+
const suffix = lastError ? ` Last Cloudflare permission-group error: ${summarizeError(lastError)}` : '';
|
|
177
|
+
throw new CloudflareControlPlaneError(`Could not resolve Cloudflare permission groups for: ${missing.join(', ')}.${suffix} Use /api/cloudflare/token/requirements to show the exact required token shape and create the operational token manually if this Cloudflare account uses different permission names.`, 'CLOUDFLARE_PERMISSION_GROUPS_MISSING', 400);
|
|
178
|
+
}
|
|
179
|
+
return Array.from(new Set(ids));
|
|
180
|
+
}
|
|
134
181
|
export function buildTokenResources(accountId, zoneId, components) {
|
|
135
182
|
const resources = {
|
|
136
183
|
[`com.cloudflare.api.account.${accountId}`]: '*',
|
|
@@ -211,6 +258,29 @@ function uniqueRequirements(requirements) {
|
|
|
211
258
|
}
|
|
212
259
|
return unique;
|
|
213
260
|
}
|
|
261
|
+
function findPermissionGroup(requirement, groups) {
|
|
262
|
+
const names = [requirement.permission, ...(requirement.alternatives ?? [])].map(normalizePermissionName);
|
|
263
|
+
const scope = cloudflareScopeForRequirement(requirement);
|
|
264
|
+
return groups.find((entry) => entry.id &&
|
|
265
|
+
entry.name &&
|
|
266
|
+
names.includes(normalizePermissionName(entry.name)) &&
|
|
267
|
+
matchesPermissionScope(entry, scope));
|
|
268
|
+
}
|
|
269
|
+
function matchesPermissionScope(group, scope) {
|
|
270
|
+
return !group.scopes || group.scopes.length === 0 || group.scopes.includes(scope);
|
|
271
|
+
}
|
|
272
|
+
function cloudflareScopeForRequirement(requirement) {
|
|
273
|
+
switch (requirement.scope) {
|
|
274
|
+
case 'account':
|
|
275
|
+
return 'com.cloudflare.api.account';
|
|
276
|
+
case 'zone':
|
|
277
|
+
return 'com.cloudflare.api.account.zone';
|
|
278
|
+
case 'user':
|
|
279
|
+
return 'com.cloudflare.api.user';
|
|
280
|
+
case 'r2':
|
|
281
|
+
return 'com.cloudflare.edge.r2.bucket';
|
|
282
|
+
}
|
|
283
|
+
}
|
|
214
284
|
function normalizePermissionName(value) {
|
|
215
285
|
return value.toLowerCase().replace(/[^a-z0-9]+/g, '');
|
|
216
286
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readFileSync } from 'node:fs';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
|
-
let version = '0.25.
|
|
3
|
+
let version = '0.25.15';
|
|
4
4
|
try {
|
|
5
5
|
const pkg = JSON.parse(readFileSync(join(import.meta.dir, '..', '..', 'package.json'), 'utf-8'));
|
|
6
6
|
version = pkg.version ?? version;
|