@nebulr-group/bridge-cli 0.5.0 → 0.5.1-beta.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 CHANGED
@@ -319,10 +319,20 @@ bridge event list --type USER_CREATED --since 24h --limit 50
319
319
 
320
320
  ```bash
321
321
  bridge setup sso --provider google --client-id <id> --client-secret <secret>
322
+ bridge setup sso --provider azure --client-id <id> --client-secret <secret> --tenant-id <entra-directory-id>
322
323
  bridge setup payments --stripe-key sk_test_xxx
323
- bridge setup communication --provider sendgrid --api-key <key> --from-address noreply@acme.com
324
+ bridge setup communication --from-address noreply@acme.com --from-name "Acme"
324
325
  ```
325
326
 
327
+ `setup sso` supports google, github, linkedin, facebook and azure (azure also
328
+ needs the Entra ID Directory (tenant) ID). SAML and OIDC are not supported by
329
+ the Bridge API; set them up in the Bridge admin UI. The command prints the
330
+ callback URL to register in the provider's console.
331
+
332
+ `setup communication` sets only the sender name and address. Bridge sends all
333
+ email through its own provider, so there is no provider or API key to
334
+ configure. A new sender address is verified by email before Bridge uses it.
335
+
326
336
  ### Info (context for AI agents)
327
337
 
328
338
  ```bash
@@ -1,3 +1,63 @@
1
1
  import { Command } from 'commander';
2
+ export declare const SSO_PROVIDERS: {
3
+ readonly google: {
4
+ readonly clientId: "googleClientId";
5
+ readonly clientSecret: "googleClientSecret";
6
+ readonly enable: "googleSsoEnabled";
7
+ };
8
+ readonly github: {
9
+ readonly clientId: "githubClientId";
10
+ readonly clientSecret: "githubClientSecret";
11
+ readonly enable: "githubSsoEnabled";
12
+ };
13
+ readonly linkedin: {
14
+ readonly clientId: "linkedinClientId";
15
+ readonly clientSecret: "linkedinClientSecret";
16
+ readonly enable: "linkedinSsoEnabled";
17
+ };
18
+ readonly facebook: {
19
+ readonly clientId: "facebookClientId";
20
+ readonly clientSecret: "facebookClientSecret";
21
+ readonly enable: "facebookSsoEnabled";
22
+ };
23
+ readonly azure: {
24
+ readonly clientId: "microsoftAzureADClientId";
25
+ readonly clientSecret: "microsoftAzureADClientSecret";
26
+ readonly tenantId: "microsoftAzureADTenantId";
27
+ readonly enable: "azureAdSsoEnabled";
28
+ };
29
+ };
30
+ export type SupportedSsoProvider = keyof typeof SSO_PROVIDERS;
31
+ /** Carries a machine-readable `code`, which `outputError` reports. */
32
+ export declare class SetupError extends Error {
33
+ readonly code: string;
34
+ constructor(message: string, code: string);
35
+ }
36
+ export interface SetupSsoOptions {
37
+ provider: string;
38
+ clientId?: string;
39
+ clientSecret?: string;
40
+ tenantId?: string;
41
+ metadataUrl?: string;
42
+ discoveryUrl?: string;
43
+ }
44
+ export declare function setupSso(opts: SetupSsoOptions): Promise<{
45
+ provider: "google" | "github" | "linkedin" | "facebook" | "azure";
46
+ enabled: boolean;
47
+ callbackUrl: string;
48
+ app: import("@nebulr-group/bridge-auth-core").AppResponse;
49
+ }>;
50
+ export interface SetupCommunicationOptions {
51
+ fromAddress?: string;
52
+ fromName?: string;
53
+ provider?: string;
54
+ apiKey?: string;
55
+ }
56
+ export declare function setupCommunication(opts: SetupCommunicationOptions): Promise<{
57
+ configured: boolean;
58
+ emailSenderEmail: string | null;
59
+ emailSenderName: string | null;
60
+ app: import("@nebulr-group/bridge-auth-core").AppResponse;
61
+ }>;
2
62
  export declare function registerSetupCommands(program: Command): void;
3
63
  //# sourceMappingURL=setup.command.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"setup.command.d.ts","sourceRoot":"","sources":["../../src/commands/setup.command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAuD5D"}
1
+ {"version":3,"file":"setup.command.d.ts","sourceRoot":"","sources":["../../src/commands/setup.command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AAuB5C,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;CAWhB,CAAC;AAEX,MAAM,MAAM,oBAAoB,GAAG,MAAM,OAAO,aAAa,CAAC;AAS9D,sEAAsE;AACtE,qBAAa,UAAW,SAAQ,KAAK;IACN,QAAQ,CAAC,IAAI,EAAE,MAAM;gBAAtC,OAAO,EAAE,MAAM,EAAW,IAAI,EAAE,MAAM;CAInD;AASD,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAsB,QAAQ,CAAC,IAAI,EAAE,eAAe;;;;;GA4CnD;AAED,MAAM,WAAW,yBAAyB;IACxC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,yBAAyB;;;;;GA+BvE;AAKD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAyC5D"}
@@ -1,25 +1,133 @@
1
+ import { Option } from 'commander';
1
2
  import { getManagementClient } from '../config.js';
2
3
  import { outputSuccess, outputError } from '../output.js';
4
+ /*
5
+ * TBP-663 — `setup sso` and `setup communication` talk to the app service
6
+ * (`app.updateCredentials` / `app.update` / `app.get`) directly instead of
7
+ * `workflows.setupSSO` / `workflows.setupCommunication`.
8
+ *
9
+ * Why not the workflows: in auth-core <= 0.7.0-beta.0 they send fields the
10
+ * API rejects under forbidNonWhitelisted — azure as `azureClientId`, saml/oidc
11
+ * as `samlMetadataUrl` / `oidcDiscoveryUrl`, email as `sendgridApiKey` — so
12
+ * both commands 400'd. auth-core main (#34) fixed them but changed their
13
+ * signatures and throws on the options this CLI used to pass. The app service
14
+ * has the same shape in both, so calling it with the server's own field names
15
+ * behaves identically whichever auth-core is installed.
16
+ *
17
+ * Field names are the server's: bridge-api
18
+ * microservices/account/nebulr-api/app/dto/update-credentials-request.dto.ts
19
+ * and update-app-request.dto.ts. Same table as auth-core's `setupSSO` and the
20
+ * MCP `setup_sso` tool. `setup-command.test.ts` pins them to those DTOs.
21
+ */
22
+ export const SSO_PROVIDERS = {
23
+ google: { clientId: 'googleClientId', clientSecret: 'googleClientSecret', enable: 'googleSsoEnabled' },
24
+ github: { clientId: 'githubClientId', clientSecret: 'githubClientSecret', enable: 'githubSsoEnabled' },
25
+ linkedin: { clientId: 'linkedinClientId', clientSecret: 'linkedinClientSecret', enable: 'linkedinSsoEnabled' },
26
+ facebook: { clientId: 'facebookClientId', clientSecret: 'facebookClientSecret', enable: 'facebookSsoEnabled' },
27
+ azure: {
28
+ clientId: 'microsoftAzureADClientId',
29
+ clientSecret: 'microsoftAzureADClientSecret',
30
+ tenantId: 'microsoftAzureADTenantId',
31
+ enable: 'azureAdSsoEnabled',
32
+ },
33
+ };
34
+ const SUPPORTED = Object.keys(SSO_PROVIDERS).join(', ');
35
+ const EMAIL = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
36
+ /** Carries a machine-readable `code`, which `outputError` reports. */
37
+ export class SetupError extends Error {
38
+ code;
39
+ constructor(message, code) {
40
+ super(message);
41
+ this.code = code;
42
+ this.name = 'SetupError';
43
+ }
44
+ }
45
+ const NOT_SAVED = ' Nothing was saved.';
46
+ const invalid = (message) => new SetupError(message + NOT_SAVED, 'INVALID_ARGUMENT');
47
+ function isSupported(provider) {
48
+ return Object.prototype.hasOwnProperty.call(SSO_PROVIDERS, provider);
49
+ }
50
+ export async function setupSso(opts) {
51
+ const provider = String(opts.provider).toLowerCase();
52
+ if (!isSupported(provider)) {
53
+ throw new SetupError(provider === 'saml' || provider === 'oidc'
54
+ ? `SSO provider "${provider}" is not supported by the Bridge API: it has no fields for SAML or OIDC ` +
55
+ `connections. Set them up in the Bridge admin UI. Supported here: ${SUPPORTED}.${NOT_SAVED}`
56
+ : `Unknown SSO provider "${provider}". Supported: ${SUPPORTED}.${NOT_SAVED}`, 'SSO_PROVIDER_NOT_SUPPORTED');
57
+ }
58
+ for (const [flag, value] of [['--metadata-url', opts.metadataUrl], ['--discovery-url', opts.discoveryUrl]]) {
59
+ if (value !== undefined) {
60
+ throw new SetupError(`${flag} was removed: the Bridge API has no field for it (SAML and OIDC are set up in the Bridge admin UI).${NOT_SAVED}`, 'SSO_PROVIDER_NOT_SUPPORTED');
61
+ }
62
+ }
63
+ if (!opts.clientId || !opts.clientSecret) {
64
+ throw invalid('--client-id and --client-secret are required (from the provider console).');
65
+ }
66
+ const fields = SSO_PROVIDERS[provider];
67
+ const credentials = {
68
+ [fields.clientId]: opts.clientId,
69
+ [fields.clientSecret]: opts.clientSecret,
70
+ };
71
+ if ('tenantId' in fields) {
72
+ if (!opts.tenantId) {
73
+ throw invalid('azure needs --tenant-id: the Directory (tenant) ID from the Entra ID app registration.');
74
+ }
75
+ credentials[fields.tenantId] = opts.tenantId;
76
+ }
77
+ else if (opts.tenantId !== undefined) {
78
+ throw invalid(`--tenant-id applies to azure only, not "${provider}".`);
79
+ }
80
+ const mgmt = getManagementClient();
81
+ await mgmt.app.updateCredentials(credentials);
82
+ const enable = { [fields.enable]: true };
83
+ await mgmt.app.update(enable);
84
+ const app = await mgmt.app.get();
85
+ return { provider, enabled: true, callbackUrl: app.defaultCallbackUri, app };
86
+ }
87
+ export async function setupCommunication(opts) {
88
+ if (opts.provider !== undefined || opts.apiKey !== undefined) {
89
+ throw new SetupError('--provider and --api-key were removed: Bridge sends all email through its own provider, so there is ' +
90
+ 'no provider or API key to configure (the Bridge API has never accepted one). ' +
91
+ `Pass only --from-address and/or --from-name.${NOT_SAVED}`, 'EMAIL_PROVIDER_NOT_SUPPORTED');
92
+ }
93
+ const { fromAddress, fromName } = opts;
94
+ if (fromAddress === undefined && fromName === undefined) {
95
+ throw invalid('Nothing to set: pass --from-address, --from-name, or both.');
96
+ }
97
+ if (fromAddress !== undefined && !EMAIL.test(fromAddress)) {
98
+ throw invalid('--from-address must be an email address, e.g. "no-reply@example.com".');
99
+ }
100
+ if (fromName !== undefined && fromName.trim() === '') {
101
+ throw invalid('--from-name must not be empty.');
102
+ }
103
+ const update = {};
104
+ if (fromAddress !== undefined)
105
+ update.emailSenderEmail = fromAddress;
106
+ if (fromName !== undefined)
107
+ update.emailSenderName = fromName;
108
+ const app = await getManagementClient().app.update(update);
109
+ return {
110
+ configured: true,
111
+ emailSenderEmail: app.emailSenderEmail ?? null,
112
+ emailSenderName: app.emailSenderName ?? null,
113
+ app,
114
+ };
115
+ }
116
+ /** Accepted only to refuse it with an explanation instead of commander's bare "unknown option". */
117
+ const removed = (flags, description) => new Option(flags, description).hideHelp();
3
118
  export function registerSetupCommands(program) {
4
119
  const setup = program.command('setup').description('Run setup workflows (multi-step operations)');
5
120
  setup.command('sso')
6
- .description('Enable an SSO provider and get callback URL')
7
- .requiredOption('--provider <provider>', 'SSO provider: google, azure, github, linkedin, facebook, saml, oidc')
8
- .option('--client-id <id>', 'OAuth client ID')
9
- .option('--client-secret <secret>', 'OAuth client secret')
10
- .option('--metadata-url <url>', 'SAML metadata URL')
11
- .option('--discovery-url <url>', 'OIDC discovery URL')
121
+ .description('Enable an SSO login provider and get the callback URL to register with it')
122
+ .requiredOption('--provider <provider>', `SSO provider: ${SUPPORTED} (SAML/OIDC are set up in the Bridge admin UI)`)
123
+ .requiredOption('--client-id <id>', 'OAuth client ID from the provider console')
124
+ .requiredOption('--client-secret <secret>', 'OAuth client secret from the provider console')
125
+ .option('--tenant-id <id>', 'azure only, required: Entra ID Directory (tenant) ID (not a Bridge tenant)')
126
+ .addOption(removed('--metadata-url <url>', 'removed: SAML is not supported by the Bridge API'))
127
+ .addOption(removed('--discovery-url <url>', 'removed: OIDC is not supported by the Bridge API'))
12
128
  .action(async (opts) => {
13
129
  try {
14
- outputSuccess(await getManagementClient().workflows.setupSSO({
15
- provider: opts.provider,
16
- config: {
17
- clientId: opts.clientId,
18
- clientSecret: opts.clientSecret,
19
- metadataUrl: opts.metadataUrl,
20
- discoveryUrl: opts.discoveryUrl,
21
- },
22
- }));
130
+ outputSuccess(await setupSso(opts));
23
131
  }
24
132
  catch (err) {
25
133
  outputError(err);
@@ -41,21 +149,14 @@ export function registerSetupCommands(program) {
41
149
  }
42
150
  });
43
151
  setup.command('communication')
44
- .description('Configure email/communication provider')
45
- .requiredOption('--provider <provider>', 'Provider name (e.g., sendgrid)')
46
- .requiredOption('--api-key <key>', 'Provider API key')
47
- .option('--from-address <email>', 'Sender email address')
48
- .option('--from-name <name>', 'Sender name')
152
+ .description("Set the sender name and address of your app's emails (sent through Bridge's own email provider)")
153
+ .option('--from-address <email>', 'Sender email address. A new address is verified by email before Bridge uses it')
154
+ .option('--from-name <name>', 'Sender display name')
155
+ .addOption(removed('--provider <provider>', 'removed: email goes through Bridge\'s own provider'))
156
+ .addOption(removed('--api-key <key>', 'removed: email goes through Bridge\'s own provider'))
49
157
  .action(async (opts) => {
50
158
  try {
51
- outputSuccess(await getManagementClient().workflows.setupCommunication({
52
- provider: opts.provider,
53
- config: {
54
- apiKey: opts.apiKey,
55
- fromAddress: opts.fromAddress,
56
- fromName: opts.fromName,
57
- },
58
- }));
159
+ outputSuccess(await setupCommunication(opts));
59
160
  }
60
161
  catch (err) {
61
162
  outputError(err);
@@ -1 +1 @@
1
- {"version":3,"file":"setup.command.js","sourceRoot":"","sources":["../../src/commands/setup.command.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAG1D,MAAM,UAAU,qBAAqB,CAAC,OAAgB;IACpD,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,WAAW,CAAC,6CAA6C,CAAC,CAAC;IAElG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;SACjB,WAAW,CAAC,6CAA6C,CAAC;SAC1D,cAAc,CAAC,uBAAuB,EAAE,qEAAqE,CAAC;SAC9G,MAAM,CAAC,kBAAkB,EAAE,iBAAiB,CAAC;SAC7C,MAAM,CAAC,0BAA0B,EAAE,qBAAqB,CAAC;SACzD,MAAM,CAAC,sBAAsB,EAAE,mBAAmB,CAAC;SACnD,MAAM,CAAC,uBAAuB,EAAE,oBAAoB,CAAC;SACrD,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QACrB,IAAI,CAAC;YACH,aAAa,CAAC,MAAM,mBAAmB,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC;gBAC3D,QAAQ,EAAE,IAAI,CAAC,QAAuB;gBACtC,MAAM,EAAE;oBACN,QAAQ,EAAE,IAAI,CAAC,QAAQ;oBACvB,YAAY,EAAE,IAAI,CAAC,YAAY;oBAC/B,WAAW,EAAE,IAAI,CAAC,WAAW;oBAC7B,YAAY,EAAE,IAAI,CAAC,YAAY;iBAChC;aACF,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,UAAU,CAAC;SACtB,WAAW,CAAC,4CAA4C,CAAC;SACzD,cAAc,CAAC,oBAAoB,EAAE,mBAAmB,CAAC;SACzD,MAAM,CAAC,2BAA2B,EAAE,mBAAmB,CAAC;SACxD,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QACrB,IAAI,CAAC;YACH,aAAa,CAAC,MAAM,mBAAmB,EAAE,CAAC,SAAS,CAAC,aAAa,CAAC;gBAChE,eAAe,EAAE,IAAI,CAAC,SAAS;gBAC/B,eAAe,EAAE,IAAI,CAAC,eAAe;aACtC,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,eAAe,CAAC;SAC3B,WAAW,CAAC,wCAAwC,CAAC;SACrD,cAAc,CAAC,uBAAuB,EAAE,gCAAgC,CAAC;SACzE,cAAc,CAAC,iBAAiB,EAAE,kBAAkB,CAAC;SACrD,MAAM,CAAC,wBAAwB,EAAE,sBAAsB,CAAC;SACxD,MAAM,CAAC,oBAAoB,EAAE,aAAa,CAAC;SAC3C,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QACrB,IAAI,CAAC;YACH,aAAa,CAAC,MAAM,mBAAmB,EAAE,CAAC,SAAS,CAAC,kBAAkB,CAAC;gBACrE,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,MAAM,EAAE;oBACN,MAAM,EAAE,IAAI,CAAC,MAAM;oBACnB,WAAW,EAAE,IAAI,CAAC,WAAW;oBAC7B,QAAQ,EAAE,IAAI,CAAC,QAAQ;iBACxB;aACF,CAAC,CAAC,CAAC;QACN,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QAAC,CAAC;IACrC,CAAC,CAAC,CAAC;AACP,CAAC"}
1
+ {"version":3,"file":"setup.command.js","sourceRoot":"","sources":["../../src/commands/setup.command.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,39 @@
1
1
  import { Command } from 'commander';
2
+ export interface ServerCredentialsState {
3
+ stripeCredentialsAdded: boolean;
4
+ /** TBP-658. Optional: older account APIs do not send it. */
5
+ stripeWebhookConfigured?: boolean;
6
+ azureMarketplaceCredentialsAdded: boolean;
7
+ azureAdSsoCredentialsAdded: boolean;
8
+ linkedinSsoCredentialsAdded: boolean;
9
+ googleSsoCredentialsAdded: boolean;
10
+ appleSsoCredentialsAdded: boolean;
11
+ githubSsoCredentialsAdded: boolean;
12
+ facebookSsoCredentialsAdded: boolean;
13
+ }
14
+ /** Webhook health fields on the app response (TBP-658). All optional: older APIs omit them. */
15
+ export interface ServerAppStripeState {
16
+ stripeSetupStatus?: 'pending' | 'completed' | 'failed' | null;
17
+ stripeSetupError?: string | null;
18
+ stripeLastWebhookAt?: string | null;
19
+ stripeLastWebhookRejectedAt?: string | null;
20
+ stripeLastWebhookRejectionReason?: string | null;
21
+ }
22
+ /** `true` only when the server confirms stored Stripe keys; never undefined. */
23
+ export declare function stripeConnectedFrom(state: unknown): boolean;
24
+ /** `null` when the API does not report it (older account API), so absence is not read as broken. */
25
+ export declare function stripeWebhookConfiguredFrom(state: unknown): boolean | null;
26
+ export interface StripeStatus {
27
+ connected: boolean;
28
+ webhookConfigured: boolean | null;
29
+ webhookHealthy: boolean | null;
30
+ lastWebhookAt: string | null;
31
+ lastWebhookRejectedAt: string | null;
32
+ lastWebhookRejectionReason: string | null;
33
+ setupStatus: string | null;
34
+ setupError: string | null;
35
+ message: string;
36
+ }
37
+ export declare function stripeStatusFrom(state: unknown, app: unknown): StripeStatus;
2
38
  export declare function registerStripeCommands(program: Command): void;
3
39
  //# sourceMappingURL=stripe.command.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"stripe.command.d.ts","sourceRoot":"","sources":["../../src/commands/stripe.command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAmC7D"}
1
+ {"version":3,"file":"stripe.command.d.ts","sourceRoot":"","sources":["../../src/commands/stripe.command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAepC,MAAM,WAAW,sBAAsB;IACrC,sBAAsB,EAAE,OAAO,CAAC;IAChC,4DAA4D;IAC5D,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,gCAAgC,EAAE,OAAO,CAAC;IAC1C,0BAA0B,EAAE,OAAO,CAAC;IACpC,2BAA2B,EAAE,OAAO,CAAC;IACrC,yBAAyB,EAAE,OAAO,CAAC;IACnC,wBAAwB,EAAE,OAAO,CAAC;IAClC,yBAAyB,EAAE,OAAO,CAAC;IACnC,2BAA2B,EAAE,OAAO,CAAC;CACtC;AAED,+FAA+F;AAC/F,MAAM,WAAW,oBAAoB;IACnC,iBAAiB,CAAC,EAAE,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,IAAI,CAAC;IAC9D,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,2BAA2B,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5C,gCAAgC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAClD;AAED,gFAAgF;AAChF,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAE3D;AAED,oGAAoG;AACpG,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,GAAG,IAAI,CAG1E;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,OAAO,CAAC;IACnB,iBAAiB,EAAE,OAAO,GAAG,IAAI,CAAC;IAClC,cAAc,EAAE,OAAO,GAAG,IAAI,CAAC;IAC/B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,0BAA0B,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1C,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;CACjB;AAyBD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,GAAG,YAAY,CAuB3E;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAqC7D"}
@@ -1,18 +1,71 @@
1
1
  import { getManagementClient } from '../config.js';
2
2
  import { outputSuccess, outputError } from '../output.js';
3
+ /** `true` only when the server confirms stored Stripe keys; never undefined. */
4
+ export function stripeConnectedFrom(state) {
5
+ return state?.stripeCredentialsAdded === true;
6
+ }
7
+ /** `null` when the API does not report it (older account API), so absence is not read as broken. */
8
+ export function stripeWebhookConfiguredFrom(state) {
9
+ const value = state?.stripeWebhookConfigured;
10
+ return typeof value === 'boolean' ? value : null;
11
+ }
12
+ const CONNECT_HINT = 'run: bridge stripe connect --secret-key sk_... --publishable-key pk_...';
13
+ const REPAIR_HINT = 'Checkout still works, but subscription changes, cancellations and payment failures are not ' +
14
+ 'reaching Bridge. Repair: re-run `bridge setup payments` with the same keys, or use "Repair ' +
15
+ 'webhook" in the Bridge admin payment settings.';
16
+ /*
17
+ * Mirrors bridge-api's `AppService._stripeWebhookUnhealthy` plus the two
18
+ * explicit failure signals. `null` = the API gave us nothing to judge by.
19
+ */
20
+ function webhookHealthy(configured, app) {
21
+ if (configured === false || app.stripeSetupStatus === 'failed')
22
+ return false;
23
+ const rejectedAt = app.stripeLastWebhookRejectedAt;
24
+ if (rejectedAt) {
25
+ const lastAt = app.stripeLastWebhookAt;
26
+ if (!lastAt || new Date(rejectedAt).getTime() > new Date(lastAt).getTime())
27
+ return false;
28
+ }
29
+ return configured;
30
+ }
31
+ export function stripeStatusFrom(state, app) {
32
+ const a = (app ?? {});
33
+ const connected = stripeConnectedFrom(state);
34
+ const webhookConfigured = stripeWebhookConfiguredFrom(state);
35
+ const healthy = connected ? webhookHealthy(webhookConfigured, a) : null;
36
+ let message;
37
+ if (!connected)
38
+ message = `Stripe is not connected — ${CONNECT_HINT}`;
39
+ else if (healthy === false)
40
+ message = `Stripe is connected, but its webhook is not working. ${REPAIR_HINT}`;
41
+ else if (healthy === null)
42
+ message = 'Stripe is connected (webhook health not reported by this API)';
43
+ else
44
+ message = 'Stripe is connected and its webhook is configured';
45
+ return {
46
+ connected,
47
+ webhookConfigured,
48
+ webhookHealthy: healthy,
49
+ lastWebhookAt: a.stripeLastWebhookAt ?? null,
50
+ lastWebhookRejectedAt: a.stripeLastWebhookRejectedAt ?? null,
51
+ lastWebhookRejectionReason: a.stripeLastWebhookRejectionReason ?? null,
52
+ setupStatus: a.stripeSetupStatus ?? null,
53
+ setupError: a.stripeSetupError ?? null,
54
+ message,
55
+ };
56
+ }
3
57
  export function registerStripeCommands(program) {
4
58
  const stripe = program.command('stripe').description('Manage Stripe integration');
5
59
  stripe.command('status')
6
- .description('Show whether Stripe credentials are configured')
60
+ .description('Show whether Stripe credentials are configured and whether its webhook works')
7
61
  .action(async () => {
8
62
  try {
9
- const state = await getManagementClient().app.getCredentialsState();
10
- outputSuccess({
11
- connected: state.hasStripeCredentials,
12
- message: state.hasStripeCredentials
13
- ? 'Stripe is connected'
14
- : 'Stripe is not connected — run: bridge stripe connect --secret-key sk_... --publishable-key pk_...',
15
- });
63
+ const client = getManagementClient();
64
+ const [state, app] = await Promise.all([
65
+ client.app.getCredentialsState(),
66
+ client.app.get(),
67
+ ]);
68
+ outputSuccess(stripeStatusFrom(state, app));
16
69
  }
17
70
  catch (err) {
18
71
  outputError(err);
@@ -28,12 +81,15 @@ export function registerStripeCommands(program) {
28
81
  stripeSecretKey: opts.secretKey,
29
82
  stripePublicKey: opts.publishableKey,
30
83
  });
31
- outputSuccess({
32
- connected: state.hasStripeCredentials,
33
- message: state.hasStripeCredentials
34
- ? 'Stripe connected successfully'
35
- : 'Credentials saved but Stripe did not confirm — check your keys and try again',
36
- });
84
+ const connected = stripeConnectedFrom(state);
85
+ const webhookConfigured = stripeWebhookConfiguredFrom(state);
86
+ let message = connected
87
+ ? 'Stripe connected successfully'
88
+ : 'Credentials saved but Stripe did not confirm — check your keys and try again';
89
+ if (connected && webhookConfigured === false) {
90
+ message += '. Warning: the Stripe webhook is not configured — run `bridge stripe status` for details';
91
+ }
92
+ outputSuccess({ connected, webhookConfigured, message });
37
93
  }
38
94
  catch (err) {
39
95
  outputError(err);
@@ -1 +1 @@
1
- {"version":3,"file":"stripe.command.js","sourceRoot":"","sources":["../../src/commands/stripe.command.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE1D,MAAM,UAAU,sBAAsB,CAAC,OAAgB;IACrD,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,2BAA2B,CAAC,CAAC;IAElF,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC;SACrB,WAAW,CAAC,gDAAgD,CAAC;SAC7D,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,mBAAmB,EAAE,CAAC,GAAG,CAAC,mBAAmB,EAAE,CAAC;YACpE,aAAa,CAAC;gBACZ,SAAS,EAAE,KAAK,CAAC,oBAAoB;gBACrC,OAAO,EAAE,KAAK,CAAC,oBAAoB;oBACjC,CAAC,CAAC,qBAAqB;oBACvB,CAAC,CAAC,mGAAmG;aACxG,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEL,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC;SACtB,WAAW,CAAC,4BAA4B,CAAC;SACzC,cAAc,CAAC,oBAAoB,EAAE,gDAAgD,CAAC;SACtF,cAAc,CAAC,yBAAyB,EAAE,qDAAqD,CAAC;SAChG,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QACrB,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,mBAAmB,EAAE,CAAC,GAAG,CAAC,iBAAiB,CAAC;gBAC9D,eAAe,EAAE,IAAI,CAAC,SAAS;gBAC/B,eAAe,EAAE,IAAI,CAAC,cAAc;aACrC,CAAC,CAAC;YACH,aAAa,CAAC;gBACZ,SAAS,EAAE,KAAK,CAAC,oBAAoB;gBACrC,OAAO,EAAE,KAAK,CAAC,oBAAoB;oBACjC,CAAC,CAAC,+BAA+B;oBACjC,CAAC,CAAC,8EAA8E;aACnF,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QAAC,CAAC;IACrC,CAAC,CAAC,CAAC;AACP,CAAC"}
1
+ {"version":3,"file":"stripe.command.js","sourceRoot":"","sources":["../../src/commands/stripe.command.ts"],"names":[],"mappings":"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"}
@@ -127,6 +127,9 @@ If any plan will have a price, connect Stripe **before** setting prices (so each
127
127
  bridge stripe status
128
128
  ```
129
129
 
130
+ If it reports `webhookHealthy: false`, checkout still works but subscription changes, cancellations
131
+ and payment failures will not sync. Tell the developer and follow the repair hint in `message`.
132
+
130
133
  If not connected, ask the developer for their Stripe keys (from `dashboard.stripe.com/apikeys`):
131
134
 
132
135
  ```bash
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nebulr-group/bridge-cli",
3
- "version": "0.5.0",
3
+ "version": "0.5.1-beta.0",
4
4
  "description": "Bridge platform CLI for AI coding agents and developers",
5
5
  "author": "Nebulr Group",
6
6
  "license": "MIT",