@nebulr-group/bridge-cli 0.6.0-beta.3 → 0.6.0-beta.5
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/commands/flag.command.d.ts.map +1 -1
- package/dist/commands/flag.command.js +19 -6
- package/dist/commands/flag.command.js.map +1 -1
- package/dist/commands/guide.command.d.ts +12 -0
- package/dist/commands/guide.command.d.ts.map +1 -1
- package/dist/commands/guide.command.js +96 -6
- package/dist/commands/guide.command.js.map +1 -1
- package/dist/commands/integration.command.d.ts +8 -0
- package/dist/commands/integration.command.d.ts.map +1 -1
- package/dist/commands/integration.command.js +92 -3
- package/dist/commands/integration.command.js.map +1 -1
- package/dist/commands/journeys.d.ts +2 -1
- package/dist/commands/journeys.d.ts.map +1 -1
- package/dist/commands/journeys.js +15 -1
- package/dist/commands/journeys.js.map +1 -1
- package/dist/commands/plan.command.d.ts +39 -0
- package/dist/commands/plan.command.d.ts.map +1 -1
- package/dist/commands/plan.command.js +134 -10
- package/dist/commands/plan.command.js.map +1 -1
- package/dist/commands/role.command.d.ts.map +1 -1
- package/dist/commands/role.command.js +2 -1
- package/dist/commands/role.command.js.map +1 -1
- package/dist/commands/tenant.command.d.ts.map +1 -1
- package/dist/commands/tenant.command.js +12 -5
- package/dist/commands/tenant.command.js.map +1 -1
- package/dist/commands/token.command.d.ts.map +1 -1
- package/dist/commands/token.command.js +6 -0
- package/dist/commands/token.command.js.map +1 -1
- package/dist/commands/user.command.d.ts.map +1 -1
- package/dist/commands/user.command.js +6 -0
- package/dist/commands/user.command.js.map +1 -1
- package/dist/flag-coherence.d.ts +42 -0
- package/dist/flag-coherence.d.ts.map +1 -0
- package/dist/flag-coherence.js +103 -0
- package/dist/flag-coherence.js.map +1 -0
- package/dist/preview.d.ts +9 -0
- package/dist/preview.d.ts.map +1 -0
- package/dist/preview.js +63 -0
- package/dist/preview.js.map +1 -0
- package/dist/prompts/auth-master-integration-prompt.md +15 -0
- package/dist/prompts/billing/master.md +20 -1
- package/dist/prompts/decisions/feature-control.md +105 -0
- package/dist/prompts/decisions/going-live.md +59 -0
- package/dist/prompts/decisions/login.md +68 -0
- package/dist/prompts/decisions/look-and-feel.md +62 -0
- package/dist/prompts/decisions/payments.md +81 -0
- package/dist/prompts/decisions/roles.md +72 -0
- package/dist/prompts/decisions/teams.md +56 -0
- package/dist/prompts/mcp-tools.json +78 -0
- package/dist/prompts/orientation.md +40 -0
- package/dist/shape.d.ts +25 -0
- package/dist/shape.d.ts.map +1 -0
- package/dist/shape.js +74 -0
- package/dist/shape.js.map +1 -0
- package/package.json +1 -1
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { getManagementClient } from '../config.js';
|
|
2
2
|
import { outputSuccess, outputError } from '../output.js';
|
|
3
3
|
import { resolvePrivilegeIds, resolveRoleId } from '../resolve.js';
|
|
4
|
+
import { shapeRoleList } from '../shape.js';
|
|
4
5
|
export function registerRoleCommands(program) {
|
|
5
6
|
const role = program.command('role').description('Manage access roles');
|
|
6
7
|
role.command('list')
|
|
7
8
|
.description('List all access roles')
|
|
8
9
|
.action(async () => {
|
|
9
10
|
try {
|
|
10
|
-
outputSuccess(await getManagementClient().roles.list());
|
|
11
|
+
outputSuccess(shapeRoleList(await getManagementClient().roles.list()));
|
|
11
12
|
}
|
|
12
13
|
catch (err) {
|
|
13
14
|
outputError(err);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"role.command.js","sourceRoot":"","sources":["../../src/commands/role.command.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"role.command.js","sourceRoot":"","sources":["../../src/commands/role.command.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tenant.command.d.ts","sourceRoot":"","sources":["../../src/commands/tenant.command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"tenant.command.d.ts","sourceRoot":"","sources":["../../src/commands/tenant.command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAkF7D"}
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { getManagementClient } from '../config.js';
|
|
2
2
|
import { outputSuccess, outputError } from '../output.js';
|
|
3
3
|
import { resolveTenantIdByName } from '../resolve.js';
|
|
4
|
+
import { shapeTenant } from '../shape.js';
|
|
5
|
+
import { dryRunPreview } from '../preview.js';
|
|
4
6
|
export function registerTenantCommands(program) {
|
|
5
7
|
const tenant = program.command('tenant').description('Manage tenants');
|
|
6
8
|
tenant.command('list')
|
|
7
9
|
.description('List all tenants')
|
|
8
10
|
.action(async () => {
|
|
9
11
|
try {
|
|
10
|
-
outputSuccess(await getManagementClient().tenants.list());
|
|
12
|
+
outputSuccess((await getManagementClient().tenants.list()).map(shapeTenant));
|
|
11
13
|
}
|
|
12
14
|
catch (err) {
|
|
13
15
|
outputError(err);
|
|
@@ -20,7 +22,7 @@ export function registerTenantCommands(program) {
|
|
|
20
22
|
.action(async (opts) => {
|
|
21
23
|
try {
|
|
22
24
|
const id = await resolveTenantIdByName({ id: opts.id, key: opts.name });
|
|
23
|
-
outputSuccess(await getManagementClient().tenants.get(id));
|
|
25
|
+
outputSuccess(shapeTenant(await getManagementClient().tenants.get(id)));
|
|
24
26
|
}
|
|
25
27
|
catch (err) {
|
|
26
28
|
outputError(err);
|
|
@@ -34,12 +36,12 @@ export function registerTenantCommands(program) {
|
|
|
34
36
|
.option('--locale <locale>', 'Locale (ISO 639-1)')
|
|
35
37
|
.action(async (opts) => {
|
|
36
38
|
try {
|
|
37
|
-
outputSuccess(await getManagementClient().tenants.create({
|
|
39
|
+
outputSuccess(shapeTenant(await getManagementClient().tenants.create({
|
|
38
40
|
owner: { email: opts.ownerEmail },
|
|
39
41
|
name: opts.name,
|
|
40
42
|
plan: opts.plan,
|
|
41
43
|
locale: opts.locale,
|
|
42
|
-
}));
|
|
44
|
+
})));
|
|
43
45
|
}
|
|
44
46
|
catch (err) {
|
|
45
47
|
outputError(err);
|
|
@@ -69,7 +71,7 @@ export function registerTenantCommands(program) {
|
|
|
69
71
|
});
|
|
70
72
|
const data = { name: renameTo, locale: opts.locale, logo: opts.logo };
|
|
71
73
|
const cleaned = Object.fromEntries(Object.entries(data).filter(([, v]) => v !== undefined));
|
|
72
|
-
outputSuccess(await getManagementClient().tenants.update(id, cleaned));
|
|
74
|
+
outputSuccess(shapeTenant(await getManagementClient().tenants.update(id, cleaned)));
|
|
73
75
|
}
|
|
74
76
|
catch (err) {
|
|
75
77
|
outputError(err);
|
|
@@ -79,9 +81,14 @@ export function registerTenantCommands(program) {
|
|
|
79
81
|
.description('Delete a tenant by --name or --id')
|
|
80
82
|
.option('--name <name>', 'Tenant name to address (alternative to --id; fails if not unique)')
|
|
81
83
|
.option('--id <id>', 'Tenant ID to address (alternative to --name)')
|
|
84
|
+
.option('--dry-run', 'Show the members, login accounts and side effects the delete would have, and delete nothing')
|
|
82
85
|
.action(async (opts) => {
|
|
83
86
|
try {
|
|
84
87
|
const id = await resolveTenantIdByName({ id: opts.id, key: opts.name });
|
|
88
|
+
if (opts.dryRun) {
|
|
89
|
+
outputSuccess(await dryRunPreview(`/v1/account/tenant/${encodeURIComponent(id)}`));
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
85
92
|
await getManagementClient().tenants.delete(id);
|
|
86
93
|
outputSuccess({ deleted: true, id });
|
|
87
94
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tenant.command.js","sourceRoot":"","sources":["../../src/commands/tenant.command.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"tenant.command.js","sourceRoot":"","sources":["../../src/commands/tenant.command.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token.command.d.ts","sourceRoot":"","sources":["../../src/commands/token.command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"token.command.d.ts","sourceRoot":"","sources":["../../src/commands/token.command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAyC5D"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getManagementClient } from '../config.js';
|
|
2
2
|
import { outputSuccess, outputError } from '../output.js';
|
|
3
3
|
import { resolveTokenIdByName } from '../resolve.js';
|
|
4
|
+
import { dryRunPreview } from '../preview.js';
|
|
4
5
|
export function registerTokenCommands(program) {
|
|
5
6
|
const token = program.command('token').description('Manage API tokens');
|
|
6
7
|
token.command('list')
|
|
@@ -34,9 +35,14 @@ export function registerTokenCommands(program) {
|
|
|
34
35
|
.description('Revoke an API token by --name or --id')
|
|
35
36
|
.option('--name <name>', 'Token name to address (alternative to --id; fails if not unique)')
|
|
36
37
|
.option('--id <id>', 'Token ID to address (alternative to --name)')
|
|
38
|
+
.option('--dry-run', 'Show the token\'s privileges and last use, and whether it is your own login, and revoke nothing')
|
|
37
39
|
.action(async (opts) => {
|
|
38
40
|
try {
|
|
39
41
|
const id = await resolveTokenIdByName({ id: opts.id, key: opts.name });
|
|
42
|
+
if (opts.dryRun) {
|
|
43
|
+
outputSuccess(await dryRunPreview(`/v1/account/api-token/app/${encodeURIComponent(id)}`));
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
40
46
|
await getManagementClient().tokens.revoke(id);
|
|
41
47
|
outputSuccess({ revoked: true, id });
|
|
42
48
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token.command.js","sourceRoot":"","sources":["../../src/commands/token.command.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"token.command.js","sourceRoot":"","sources":["../../src/commands/token.command.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,MAAM,UAAU,qBAAqB,CAAC,OAAgB;IACpD,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,WAAW,CAAC,mBAAmB,CAAC,CAAC;IAExE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;SAClB,WAAW,CAAC,qBAAqB,CAAC;SAClC,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,IAAI,CAAC;YAAC,aAAa,CAAC,MAAM,mBAAmB,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;QAAC,CAAC;QACjE,OAAO,GAAG,EAAE,CAAC;YAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEL,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;SACpB,WAAW,CAAC,wBAAwB,CAAC;SACrC,cAAc,CAAC,eAAe,EAAE,YAAY,CAAC;SAC7C,MAAM,CAAC,qBAAqB,EAAE,gCAAgC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;SACpF,MAAM,CAAC,oBAAoB,EAAE,8BAA8B,CAAC;SAC5D,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QACrB,IAAI,CAAC;YACH,aAAa,CAAC,MAAM,mBAAmB,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC;gBACtD,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,UAAU,EAAE,IAAI,CAAC,UAAU,IAAI,EAAE;gBACjC,QAAQ,EAAE,IAAI,CAAC,QAAQ;aACxB,CAAC,CAAC,CAAC;QACN,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEL,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;SACpB,WAAW,CAAC,uCAAuC,CAAC;SACpD,MAAM,CAAC,eAAe,EAAE,kEAAkE,CAAC;SAC3F,MAAM,CAAC,WAAW,EAAE,6CAA6C,CAAC;SAClE,MAAM,CAAC,WAAW,EAAE,iGAAiG,CAAC;SACtH,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QACrB,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,MAAM,oBAAoB,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;YACvE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gBAChB,aAAa,CAAC,MAAM,aAAa,CAAC,6BAA6B,kBAAkB,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;gBAC1F,OAAO;YACT,CAAC;YACD,MAAM,mBAAmB,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAC9C,aAAa,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;QACvC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QAAC,CAAC;IACrC,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user.command.d.ts","sourceRoot":"","sources":["../../src/commands/user.command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"user.command.d.ts","sourceRoot":"","sources":["../../src/commands/user.command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAqF3D"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getManagementClient, resolveTenantId } from '../config.js';
|
|
2
2
|
import { outputSuccess, outputError } from '../output.js';
|
|
3
3
|
import { resolveUserId } from '../resolve.js';
|
|
4
|
+
import { dryRunPreview } from '../preview.js';
|
|
4
5
|
export function registerUserCommands(program) {
|
|
5
6
|
const user = program.command('user').description('Manage tenant users');
|
|
6
7
|
user.command('list')
|
|
@@ -75,10 +76,15 @@ export function registerUserCommands(program) {
|
|
|
75
76
|
.option('--email <email>', 'User email to address (alternative to --user-id)')
|
|
76
77
|
.option('--user-id <id>', 'User ID to address (alternative to --email)')
|
|
77
78
|
.option('--tenant-id <id>', 'Tenant ID (or set BRIDGE_TENANT_ID)')
|
|
79
|
+
.option('--dry-run', 'Show whether their login account goes too and whether they are the last owner, and remove nothing')
|
|
78
80
|
.action(async (opts) => {
|
|
79
81
|
try {
|
|
80
82
|
const tenantId = resolveTenantId(opts);
|
|
81
83
|
const userId = await resolveUserId({ id: opts.userId, key: opts.email }, tenantId);
|
|
84
|
+
if (opts.dryRun) {
|
|
85
|
+
outputSuccess(await dryRunPreview(`/v1/account/tenant/user/${encodeURIComponent(userId)}`, { 'x-tenant-id': tenantId }));
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
82
88
|
await getManagementClient().users.remove(tenantId, userId);
|
|
83
89
|
outputSuccess({ removed: true, userId });
|
|
84
90
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user.command.js","sourceRoot":"","sources":["../../src/commands/user.command.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"user.command.js","sourceRoot":"","sources":["../../src/commands/user.command.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { Rule } from '@nebulr-group/bridge-auth-core';
|
|
2
|
+
/** The fields a coherence check reads. Values as stored; defaults applied here. */
|
|
3
|
+
export interface FlagLike {
|
|
4
|
+
key: string;
|
|
5
|
+
state?: string;
|
|
6
|
+
valueType?: string;
|
|
7
|
+
onValue?: unknown;
|
|
8
|
+
offValue?: unknown;
|
|
9
|
+
rule?: Rule | null;
|
|
10
|
+
}
|
|
11
|
+
/** What the app actually has, for the dangling-reference check. */
|
|
12
|
+
export interface CoherenceCatalog {
|
|
13
|
+
/** Rules compare the KEY; the name is kept to say which key was meant. */
|
|
14
|
+
plans: Array<{
|
|
15
|
+
key: string;
|
|
16
|
+
name?: string;
|
|
17
|
+
}>;
|
|
18
|
+
roles: Array<{
|
|
19
|
+
key: string;
|
|
20
|
+
name?: string;
|
|
21
|
+
}>;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The warnings for one flag. Pure. `catalog` omitted skips the
|
|
25
|
+
* dangling-reference check (the caller could not read plans/roles).
|
|
26
|
+
*/
|
|
27
|
+
export declare function flagCoherenceWarnings(flag: FlagLike, catalog?: CoherenceCatalog): string[];
|
|
28
|
+
/** True when any condition reads a plan or role attribute (worth fetching the catalog). */
|
|
29
|
+
export declare function ruleReadsPlanOrRole(rule: Rule | null | undefined): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Plans and roles for the dangling-reference check. Never throws: a login
|
|
32
|
+
* that cannot read plans or roles gets no dangling-reference warning rather
|
|
33
|
+
* than a failed flag command — a warning never blocks.
|
|
34
|
+
*/
|
|
35
|
+
export declare function loadCoherenceCatalog(): Promise<CoherenceCatalog | undefined>;
|
|
36
|
+
/** Warnings for a list of flags, fetching the catalog once and only if a rule needs it. */
|
|
37
|
+
export declare function warningsForFlags(flags: FlagLike[]): Promise<string[][]>;
|
|
38
|
+
/** A flag with its warnings attached — only when there are any, so a coherent flag prints as before. */
|
|
39
|
+
export declare function withFlagWarnings<T extends FlagLike>(flag: T): Promise<T | (T & {
|
|
40
|
+
warnings: string[];
|
|
41
|
+
})>;
|
|
42
|
+
//# sourceMappingURL=flag-coherence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flag-coherence.d.ts","sourceRoot":"","sources":["../src/flag-coherence.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gCAAgC,CAAC;AAgB3D,mFAAmF;AACnF,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;CACpB;AAED,mEAAmE;AACnE,MAAM,WAAW,gBAAgB;IAC/B,0EAA0E;IAC1E,KAAK,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC7C,KAAK,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC9C;AAiBD;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,MAAM,EAAE,CAuD1F;AAED,2FAA2F;AAC3F,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAO1E;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAWlF;AAED,2FAA2F;AAC3F,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAG7E;AAED,wGAAwG;AACxG,wBAAsB,gBAAgB,CAAC,CAAC,SAAS,QAAQ,EAAE,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG;IAAE,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAAC,CAI7G"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { getManagementClient } from './config.js';
|
|
2
|
+
/** Attributes whose value names a plan (the JWT `plan` claim, billing slug). */
|
|
3
|
+
const PLAN_ATTRIBUTES = ['tenant.plan', 'bridge:billing.plan'];
|
|
4
|
+
/** Attributes whose value names a role (the JWT `role` claim). */
|
|
5
|
+
const ROLE_ATTRIBUTES = ['user.role'];
|
|
6
|
+
/** Operators whose values are compared for equality with the attribute. */
|
|
7
|
+
const EQUALITY_OPERATORS = ['eq', 'neq', 'in', 'not_in'];
|
|
8
|
+
function sameValue(a, b) {
|
|
9
|
+
return JSON.stringify(a ?? null) === JSON.stringify(b ?? null);
|
|
10
|
+
}
|
|
11
|
+
function listed(entries) {
|
|
12
|
+
return entries.length ? entries.map((e) => e.key).join(', ') : '(none)';
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The warnings for one flag. Pure. `catalog` omitted skips the
|
|
16
|
+
* dangling-reference check (the caller could not read plans/roles).
|
|
17
|
+
*/
|
|
18
|
+
export function flagCoherenceWarnings(flag, catalog) {
|
|
19
|
+
const warnings = [];
|
|
20
|
+
const state = flag.state ?? 'off';
|
|
21
|
+
const valueType = flag.valueType ?? 'boolean';
|
|
22
|
+
const onValue = flag.onValue !== undefined ? flag.onValue : true;
|
|
23
|
+
const offValue = flag.offValue !== undefined ? flag.offValue : false;
|
|
24
|
+
if (state === 'on') {
|
|
25
|
+
if (valueType === 'boolean' && onValue === false) {
|
|
26
|
+
warnings.push(`Flag "${flag.key}" is switched on, but its onValue is false, so it returns false for ` +
|
|
27
|
+
'everyone: it looks on and behaves off. Set onValue to true, or switch the flag off.');
|
|
28
|
+
}
|
|
29
|
+
else if (sameValue(onValue, offValue)) {
|
|
30
|
+
warnings.push(`Flag "${flag.key}" is switched on, but its onValue equals its offValue ` +
|
|
31
|
+
`(${JSON.stringify(onValue)}), so switching it on or off changes nothing.`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (catalog && flag.rule) {
|
|
35
|
+
for (const branch of flag.rule.branches ?? []) {
|
|
36
|
+
for (const condition of branch.conditions ?? []) {
|
|
37
|
+
if (!EQUALITY_OPERATORS.includes(condition.operator))
|
|
38
|
+
continue;
|
|
39
|
+
const isPlan = PLAN_ATTRIBUTES.includes(condition.attribute);
|
|
40
|
+
const isRole = ROLE_ATTRIBUTES.includes(condition.attribute);
|
|
41
|
+
if (!isPlan && !isRole)
|
|
42
|
+
continue;
|
|
43
|
+
const known = isPlan ? catalog.plans : catalog.roles;
|
|
44
|
+
const keys = new Set(known.map((k) => k.key));
|
|
45
|
+
const what = isPlan ? 'plan' : 'role';
|
|
46
|
+
for (const value of condition.values ?? []) {
|
|
47
|
+
if (typeof value !== 'string' || keys.has(value))
|
|
48
|
+
continue;
|
|
49
|
+
// The token carries the plan/role KEY, so a display name never matches.
|
|
50
|
+
const byName = known.find((k) => k.name === value);
|
|
51
|
+
if (byName) {
|
|
52
|
+
warnings.push(`Flag "${flag.key}" has a rule on ${condition.attribute} ${condition.operator} ` +
|
|
53
|
+
`"${value}", which matches the ${what} named "${value}" by name; rules compare the ` +
|
|
54
|
+
`${what} key — use "${byName.key}".`);
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
warnings.push(`Flag "${flag.key}" has a rule on ${condition.attribute} ${condition.operator} ` +
|
|
58
|
+
`"${value}", but the app has no ${what} "${value}", so no real ` +
|
|
59
|
+
`${isPlan ? 'workspace' : 'user'} can carry it. Existing ${what} keys: ` +
|
|
60
|
+
`${listed(known)}.`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return warnings;
|
|
66
|
+
}
|
|
67
|
+
/** True when any condition reads a plan or role attribute (worth fetching the catalog). */
|
|
68
|
+
export function ruleReadsPlanOrRole(rule) {
|
|
69
|
+
if (!rule)
|
|
70
|
+
return false;
|
|
71
|
+
return (rule.branches ?? []).some((b) => (b.conditions ?? []).some((c) => PLAN_ATTRIBUTES.includes(c.attribute) || ROLE_ATTRIBUTES.includes(c.attribute)));
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Plans and roles for the dangling-reference check. Never throws: a login
|
|
75
|
+
* that cannot read plans or roles gets no dangling-reference warning rather
|
|
76
|
+
* than a failed flag command — a warning never blocks.
|
|
77
|
+
*/
|
|
78
|
+
export async function loadCoherenceCatalog() {
|
|
79
|
+
try {
|
|
80
|
+
const client = getManagementClient();
|
|
81
|
+
const [plans, roles] = await Promise.all([client.plans.list(), client.roles.list()]);
|
|
82
|
+
return {
|
|
83
|
+
plans: (plans ?? []).map((p) => ({ key: String(p.key), name: p.name })),
|
|
84
|
+
roles: (roles ?? []).map((r) => ({ key: String(r.key), name: r.name })),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/** Warnings for a list of flags, fetching the catalog once and only if a rule needs it. */
|
|
92
|
+
export async function warningsForFlags(flags) {
|
|
93
|
+
const catalog = flags.some((f) => ruleReadsPlanOrRole(f.rule)) ? await loadCoherenceCatalog() : undefined;
|
|
94
|
+
return flags.map((f) => flagCoherenceWarnings(f, catalog));
|
|
95
|
+
}
|
|
96
|
+
/** A flag with its warnings attached — only when there are any, so a coherent flag prints as before. */
|
|
97
|
+
export async function withFlagWarnings(flag) {
|
|
98
|
+
if (!flag || typeof flag !== 'object')
|
|
99
|
+
return flag;
|
|
100
|
+
const [warnings] = await warningsForFlags([flag]);
|
|
101
|
+
return warnings.length ? { ...flag, warnings } : flag;
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=flag-coherence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flag-coherence.js","sourceRoot":"","sources":["../src/flag-coherence.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare class PreviewNotSupportedError extends Error {
|
|
2
|
+
readonly path: string;
|
|
3
|
+
readonly serverBody?: unknown | undefined;
|
|
4
|
+
readonly code = "PREVIEW_NOT_SUPPORTED";
|
|
5
|
+
constructor(path: string, serverBody?: unknown | undefined);
|
|
6
|
+
}
|
|
7
|
+
export declare function previewPath(path: string): string;
|
|
8
|
+
export declare function dryRunPreview(path: string, headers?: Record<string, string>): Promise<unknown>;
|
|
9
|
+
//# sourceMappingURL=preview.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview.d.ts","sourceRoot":"","sources":["../src/preview.ts"],"names":[],"mappings":"AAmBA,qBAAa,wBAAyB,SAAQ,KAAK;IAErC,QAAQ,CAAC,IAAI,EAAE,MAAM;IAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO;IADhE,QAAQ,CAAC,IAAI,2BAA2B;gBACnB,IAAI,EAAE,MAAM,EAAW,UAAU,CAAC,EAAE,OAAO,YAAA;CAOjE;AAcD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAgBpG"}
|
package/dist/preview.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { HttpError } from '@nebulr-group/bridge-auth-core';
|
|
2
|
+
import { getManagementHttp } from './config.js';
|
|
3
|
+
/*
|
|
4
|
+
* TBP-709 (E) — `--dry-run` on the destructive commands.
|
|
5
|
+
*
|
|
6
|
+
* The preview is the server's: every delete route has a read-only sibling,
|
|
7
|
+
* `GET <route>/deletion-preview`, that answers with what the delete would
|
|
8
|
+
* remove and removes nothing. It passes the same guards as the delete, so a
|
|
9
|
+
* login without the destructive privilege gets the same 403 — and it is the
|
|
10
|
+
* same answer the MCP tools' `dryRun` shows.
|
|
11
|
+
*
|
|
12
|
+
* Why a GET on its own path, and never `?dryRun=true` on the DELETE: this CLI
|
|
13
|
+
* is released separately from the server and is pointed at servers that
|
|
14
|
+
* predate previews. Such a server ignores an unknown query parameter and
|
|
15
|
+
* PERFORMS THE DELETE; it answers an unknown path with 404. So a 404 here
|
|
16
|
+
* means "no previews on this server", and the command stops — it never falls
|
|
17
|
+
* back to the delete.
|
|
18
|
+
*/
|
|
19
|
+
export class PreviewNotSupportedError extends Error {
|
|
20
|
+
path;
|
|
21
|
+
serverBody;
|
|
22
|
+
code = 'PREVIEW_NOT_SUPPORTED';
|
|
23
|
+
constructor(path, serverBody) {
|
|
24
|
+
super(`This Bridge server does not support deletion previews yet (GET ${path} answered 404). ` +
|
|
25
|
+
'Nothing was deleted. Run without --dry-run only if you mean to delete.');
|
|
26
|
+
this.path = path;
|
|
27
|
+
this.serverBody = serverBody;
|
|
28
|
+
this.name = 'PreviewNotSupportedError';
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/*
|
|
32
|
+
* A server that HAS the route still 404s a record that does not exist, with
|
|
33
|
+
* its own message ("tenant not found"). An unknown route gets the framework's
|
|
34
|
+
* "Cannot GET …" (or a bare "Not Found" from a proxy in front). Only the
|
|
35
|
+
* former is passed through as-is; either way the command fails and deletes
|
|
36
|
+
* nothing — this only decides which message the user reads.
|
|
37
|
+
*/
|
|
38
|
+
function isRecordNotFound(body) {
|
|
39
|
+
const message = body && typeof body === 'object' ? body.message : undefined;
|
|
40
|
+
return typeof message === 'string' && !/^Cannot GET\b/.test(message) && message !== 'Not Found';
|
|
41
|
+
}
|
|
42
|
+
export function previewPath(path) {
|
|
43
|
+
return `${path}/deletion-preview`;
|
|
44
|
+
}
|
|
45
|
+
export async function dryRunPreview(path, headers) {
|
|
46
|
+
const route = previewPath(path);
|
|
47
|
+
let preview;
|
|
48
|
+
try {
|
|
49
|
+
preview = await getManagementHttp().get(route, headers);
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
if (err instanceof HttpError && err.status === 404 && !isRecordNotFound(err.body)) {
|
|
53
|
+
throw new PreviewNotSupportedError(route, err.body);
|
|
54
|
+
}
|
|
55
|
+
throw err;
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
...(preview && typeof preview === 'object' ? preview : {}),
|
|
59
|
+
dryRun: true,
|
|
60
|
+
next: 'Nothing was changed. Run the same command without --dry-run to go ahead.',
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=preview.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview.js","sourceRoot":"","sources":["../src/preview.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IAE5B;IAAuB;IADnC,IAAI,GAAG,uBAAuB,CAAC;IACxC,YAAqB,IAAY,EAAW,UAAoB;QAC9D,KAAK,CACH,kEAAkE,IAAI,kBAAkB;YACtF,wEAAwE,CAC3E,CAAC;QAJiB,SAAI,GAAJ,IAAI,CAAQ;QAAW,eAAU,GAAV,UAAU,CAAU;QAK9D,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;IACzC,CAAC;CACF;AAED;;;;;;GAMG;AACH,SAAS,gBAAgB,CAAC,IAAa;IACrC,MAAM,OAAO,GAAG,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAE,IAA8B,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;IACvG,OAAO,OAAO,OAAO,KAAK,QAAQ,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,OAAO,KAAK,WAAW,CAAC;AAClG,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,GAAG,IAAI,mBAAmB,CAAC;AACpC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAY,EAAE,OAAgC;IAChF,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IAChC,IAAI,OAAgC,CAAC;IACrC,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,iBAAiB,EAAE,CAAC,GAAG,CAA0B,KAAK,EAAE,OAAO,CAAC,CAAC;IACnF,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,SAAS,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAClF,MAAM,IAAI,wBAAwB,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;QACtD,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;IACD,OAAO;QACL,GAAG,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1D,MAAM,EAAE,IAAI;QACZ,IAAI,EAAE,0EAA0E;KACjF,CAAC;AACJ,CAAC"}
|
|
@@ -14,6 +14,21 @@ This prompt is framework-agnostic. It orchestrates discovery, confirmation, and
|
|
|
14
14
|
|
|
15
15
|
Run `bridge auth login` and wait for it to print "Logged in as <email>". Once it exits, proceed to Step 1.
|
|
16
16
|
|
|
17
|
+
**Connected through the Bridge MCP server instead?** Skip the login: the connection is already signed in to one app. Every CLI step below has a tool; use the tool and do not translate by hand.
|
|
18
|
+
|
|
19
|
+
| Operation | MCP | CLI |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| What Bridge does, to relay to the developer | `get_started` | `bridge guide orientation` |
|
|
22
|
+
| Read the app: id, URLs, redirect URIs (Step 3) | `get_app` | `bridge app get` |
|
|
23
|
+
| Read the login methods (Step 3) | `get_auth_config` | `bridge info auth-config` |
|
|
24
|
+
| Set the frontend URL, callback and allowed origins (Step 3b) | `update_app` (`uiUrl`, `defaultCallbackUri`, `allowedOrigins`); `allowedOrigins` replaces the whole list, so send every origin | `bridge app update --ui-url … --default-callback-uri … --allowed-origins …` |
|
|
25
|
+
| Add one redirect URI, keeping the others (Step 3b) | `add_redirect_uri` | `bridge app redirect-uris add <url>` |
|
|
26
|
+
| This prompt | `get_integration_guide` (topic `master`) | `bridge guide` |
|
|
27
|
+
| A per-framework guide (Step 4) | `get_integration_guide` (topic `auth`) with the framework; topic `integration` for the hosted setup | `bridge guide <framework> sdk-auth` / `bridge guide <framework>` |
|
|
28
|
+
| Check the project's env vars against the app (Step 6) | `diagnose_integration` | `bridge diagnose` |
|
|
29
|
+
| Prove a real sign-in works (Step 6) | `create_test_user`, then `verify_login` | `bridge test-user create`, then `bridge test-user verify` |
|
|
30
|
+
| Roles and flags for route protection (Step 5) | `list_roles`, `list_feature_flags` | `bridge role list`, `bridge flag list` |
|
|
31
|
+
|
|
17
32
|
---
|
|
18
33
|
|
|
19
34
|
**At the end of this integration you will output a success message that looks like this:**
|
|
@@ -13,6 +13,22 @@ This prompt is framework-agnostic. It orchestrates discovery, pricing model setu
|
|
|
13
13
|
|
|
14
14
|
Run `bridge auth login` and wait for it to print "Logged in as <email>". Once it exits, proceed to Step 1.
|
|
15
15
|
|
|
16
|
+
**Connected through the Bridge MCP server instead?** Skip the login: the connection is already signed in to one app. Every CLI step below has a tool; use the tool and do not translate by hand.
|
|
17
|
+
|
|
18
|
+
| Operation | MCP | CLI |
|
|
19
|
+
|---|---|---|
|
|
20
|
+
| List plans with prices and quotas | `list_plans` | `bridge plan list` |
|
|
21
|
+
| Create a plan, or reshape one in one call | `create_plan`, or `apply_plan` (prices, quotas and trial together) | `bridge plan create` |
|
|
22
|
+
| Is Stripe connected and receiving webhooks? | `get_stripe_status` | `bridge stripe status` |
|
|
23
|
+
| Connect Stripe and switch payments on | `setup_payments` | `bridge setup payments` |
|
|
24
|
+
| Add or change a price | `set_plan_price` | `bridge plan price set` |
|
|
25
|
+
| Add or change a quota | `set_plan_quota` (`policy` hard or metered, `kind` counter or gauge) | `bridge plan quota set` |
|
|
26
|
+
| List every metric with its kind | `list_plan_quotas` | `bridge plan quota list` |
|
|
27
|
+
| Keep plan-less users out of the paywall | `update_app` (`paymentsAutoRedirect: false`) | `bridge app update --payments-auto-redirect false` |
|
|
28
|
+
| This prompt | `get_integration_guide` (topic `billing-master`) | `bridge guide billing` |
|
|
29
|
+
| A per-framework billing guide (Step 4) | `get_integration_guide` (topic `billing`) with the framework | `bridge guide billing --framework <name>` |
|
|
30
|
+
| How limits are enforced end to end | `get_integration_guide` (topic `mechanisms`) | `bridge guide mechanisms` |
|
|
31
|
+
|
|
16
32
|
## Step 1 — Discover projects
|
|
17
33
|
|
|
18
34
|
Scan the current directory and its immediate subdirectories for `package.json` files. For each one:
|
|
@@ -141,9 +157,12 @@ and payment failures will not sync. Tell the developer and follow the repair hin
|
|
|
141
157
|
If not connected, ask the developer for their Stripe keys (from `dashboard.stripe.com/apikeys`):
|
|
142
158
|
|
|
143
159
|
```bash
|
|
144
|
-
bridge
|
|
160
|
+
bridge setup payments --stripe-key sk_test_... --stripe-public-key pk_test_...
|
|
145
161
|
```
|
|
146
162
|
|
|
163
|
+
This stores the keys **and** switches payments on in one step. (`bridge stripe connect` only
|
|
164
|
+
stores the keys and leaves payments off.)
|
|
165
|
+
|
|
147
166
|
Now set any **remaining** prices — one command per Prices-table row not already covered by the
|
|
148
167
|
`plan create` call above. `plan price set` is idempotent (keyed on currency + interval), so a
|
|
149
168
|
tier with monthly **and** yearly pricing is just one more call against the same plan key:
|