@nebulr-group/bridge-cli 0.6.0-beta.1 → 0.6.0-beta.3
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 +8 -2
- package/dist/commands/guide.command.d.ts +3 -0
- package/dist/commands/guide.command.d.ts.map +1 -1
- package/dist/commands/guide.command.js +65 -0
- package/dist/commands/guide.command.js.map +1 -1
- package/dist/commands/journeys.d.ts +42 -0
- package/dist/commands/journeys.d.ts.map +1 -0
- package/dist/commands/journeys.js +204 -0
- package/dist/commands/journeys.js.map +1 -0
- package/dist/prompts/auth-master-integration-prompt.md +7 -5
- package/dist/prompts/billing/master.md +31 -17
- package/dist/prompts/flags/master.md +8 -8
- package/dist/prompts/integration-success.md +4 -5
- package/dist/prompts/mechanisms.md +284 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -142,8 +142,8 @@ One more, for working on the integration guides themselves:
|
|
|
142
142
|
export BRIDGE_GUIDE_LOCAL_DIR=/path/to/thebridge-platform/bridge-plugins
|
|
143
143
|
```
|
|
144
144
|
|
|
145
|
-
`bridge guide`
|
|
146
|
-
instead of fetching them from GitHub, so edits show up without a release.
|
|
145
|
+
`bridge guide` then reads prompts from that directory
|
|
146
|
+
instead of fetching them from GitHub (or the copies bundled with the CLI), so edits show up without a release.
|
|
147
147
|
|
|
148
148
|
## Usage
|
|
149
149
|
|
|
@@ -355,6 +355,12 @@ bridge guide flags # Feature Flags 2.0 master prompt
|
|
|
355
355
|
bridge guide billing # Billing 2.0 master prompt (subscriptions, quotas, webhooks)
|
|
356
356
|
```
|
|
357
357
|
|
|
358
|
+
One page explains the mechanisms all of them build on — the server decides limits and the client decorates, a POST increments the limit, counter vs gauge, the three ways to show a limit in the UI, and the four levels of customising Bridge's pages:
|
|
359
|
+
|
|
360
|
+
```bash
|
|
361
|
+
bridge guide mechanisms
|
|
362
|
+
```
|
|
363
|
+
|
|
358
364
|
Per-framework guides:
|
|
359
365
|
|
|
360
366
|
```bash
|
|
@@ -17,6 +17,9 @@ type FlagsFramework = (typeof FLAGS_FRAMEWORKS)[number];
|
|
|
17
17
|
declare const BILLING_FRAMEWORKS: readonly ["svelte", "react", "nextjs", "angular", "nestjs", "express"];
|
|
18
18
|
type BillingFramework = (typeof BILLING_FRAMEWORKS)[number];
|
|
19
19
|
export declare function registerGuideCommands(program: Command): void;
|
|
20
|
+
export declare const MECHANISMS_PROMPT_FILENAME = "mechanisms.md";
|
|
21
|
+
/** The mechanisms page, bundled with the CLI (`BRIDGE_GUIDE_LOCAL_DIR` wins in development). */
|
|
22
|
+
export declare function fetchMechanismsGuide(): Promise<string>;
|
|
20
23
|
/**
|
|
21
24
|
* Detect framework from package.json so `bridge guide flags` can be called
|
|
22
25
|
* bare. Same heuristic order as `bridge flag init`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guide.command.d.ts","sourceRoot":"","sources":["../../src/commands/guide.command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"guide.command.d.ts","sourceRoot":"","sources":["../../src/commands/guide.command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAkCpC,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CACtC,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,IAAI,aAAa,CAejD;AAED,QAAA,MAAM,gBAAgB,wEAAyE,CAAC;AAChG,KAAK,cAAc,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAExD,QAAA,MAAM,kBAAkB,wEAAyE,CAAC;AAClG,KAAK,gBAAgB,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC;AAyB5D,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAmL5D;AAED,eAAO,MAAM,0BAA0B,kBAAkB,CAAC;AAE1D,gGAAgG;AAChG,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,MAAM,CAAC,CAsB5D;AAkBD;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CA0BrC;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,MAAM,CAAC,CAE9D;AAED,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,MAAM,CAAC,CAEhE;AAqCD;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CA0BvC"}
|
|
@@ -4,6 +4,7 @@ import { join } from 'node:path';
|
|
|
4
4
|
import { commandsDir } from './runtime-dir.js';
|
|
5
5
|
import { outputSuccess, outputPrompt, outputError } from '../output.js';
|
|
6
6
|
import { AUTH_MASTER_PROMPT_FILENAME, AUTH_MASTER_PROMPT_URL, pluginGuideUrl } from '../prompt-urls.js';
|
|
7
|
+
import { fetchDecisionGuide, registerJourneyCommands, unknownGuideMessage } from './journeys.js';
|
|
7
8
|
/**
|
|
8
9
|
* Locate the directory containing this module on disk so the bundled prompts
|
|
9
10
|
* (shipped at `dist/prompts/`) can be read relative to it. The `import.meta`
|
|
@@ -82,6 +83,15 @@ export function registerGuideCommands(program) {
|
|
|
82
83
|
.action(async (_opts, command) => {
|
|
83
84
|
try {
|
|
84
85
|
const opts = command.optsWithGlobals();
|
|
86
|
+
// TBP-712: `bridge guide <anything unknown>` used to fall through to
|
|
87
|
+
// here and print the master as if the lookup had worked. Name what
|
|
88
|
+
// exists instead.
|
|
89
|
+
const [unknown] = command.args;
|
|
90
|
+
if (unknown) {
|
|
91
|
+
throw Object.assign(new Error(unknownGuideMessage(unknown, Object.keys(GUIDE_REPOS))), {
|
|
92
|
+
code: 'GUIDE_NOT_FOUND',
|
|
93
|
+
});
|
|
94
|
+
}
|
|
85
95
|
// No login here: reading a guide needs no session, and the commands
|
|
86
96
|
// the guide goes on to run ask for one themselves (TBP-706).
|
|
87
97
|
const guide = await fetchMasterPrompt();
|
|
@@ -200,6 +210,13 @@ export function registerGuideCommands(program) {
|
|
|
200
210
|
}
|
|
201
211
|
});
|
|
202
212
|
}
|
|
213
|
+
// TBP-712 — the seven journeys by name, composed like the MCP prompts.
|
|
214
|
+
registerJourneyCommands(guide, {
|
|
215
|
+
decision: fetchDecisionGuide,
|
|
216
|
+
master: (m) => m === 'auth' ? fetchMasterPrompt() : m === 'flags' ? fetchFlagsMasterPrompt() : fetchBillingMasterPrompt(),
|
|
217
|
+
frameworkGuide: (tech, feature) => fetchGuide(tech, feature),
|
|
218
|
+
coverage: () => loadGuideCoverage().frameworks,
|
|
219
|
+
}, resolveFlagsFramework);
|
|
203
220
|
guide.command('custom')
|
|
204
221
|
.description('Universal integration guide for any technology using REST API + JWKS')
|
|
205
222
|
.option('--json', 'Emit a JSON envelope instead of the raw markdown prompt')
|
|
@@ -210,6 +227,27 @@ export function registerGuideCommands(program) {
|
|
|
210
227
|
else
|
|
211
228
|
outputPrompt(CUSTOM_GUIDE);
|
|
212
229
|
});
|
|
230
|
+
// TBP-705 — the mechanisms every guide builds on: the server decides, a POST
|
|
231
|
+
// increments the limit, counter vs gauge, the three UI levels, the four
|
|
232
|
+
// customisation rungs, self-reported usage. The MCP server serves the same
|
|
233
|
+
// file (bridge-cli/main/bridge-cli/prompts/mechanisms.md) as
|
|
234
|
+
// `get_integration_guide topic=mechanisms`.
|
|
235
|
+
guide.command('mechanisms')
|
|
236
|
+
.description('How Bridge works: limits, counter vs gauge, UI levels, customisation rungs')
|
|
237
|
+
.option('--json', 'Emit a JSON envelope instead of the raw markdown prompt')
|
|
238
|
+
.action(async (_opts, command) => {
|
|
239
|
+
try {
|
|
240
|
+
const opts = command.optsWithGlobals();
|
|
241
|
+
const content = await fetchMechanismsGuide();
|
|
242
|
+
if (opts.json)
|
|
243
|
+
outputSuccess({ topic: 'mechanisms', guide: content });
|
|
244
|
+
else
|
|
245
|
+
outputPrompt(content);
|
|
246
|
+
}
|
|
247
|
+
catch (err) {
|
|
248
|
+
outputError(err);
|
|
249
|
+
}
|
|
250
|
+
});
|
|
213
251
|
guide.command('integration-success')
|
|
214
252
|
.description('Integration success message template — output at the end of a completed integration')
|
|
215
253
|
.option('--json', 'Emit a JSON envelope instead of the raw markdown prompt')
|
|
@@ -227,6 +265,33 @@ export function registerGuideCommands(program) {
|
|
|
227
265
|
}
|
|
228
266
|
});
|
|
229
267
|
}
|
|
268
|
+
export const MECHANISMS_PROMPT_FILENAME = 'mechanisms.md';
|
|
269
|
+
/** The mechanisms page, bundled with the CLI (`BRIDGE_GUIDE_LOCAL_DIR` wins in development). */
|
|
270
|
+
export async function fetchMechanismsGuide() {
|
|
271
|
+
const localDir = process.env.BRIDGE_GUIDE_LOCAL_DIR;
|
|
272
|
+
if (localDir) {
|
|
273
|
+
try {
|
|
274
|
+
return await readFile(join(localDir, 'bridge-cli', 'bridge-cli', 'prompts', MECHANISMS_PROMPT_FILENAME), 'utf-8');
|
|
275
|
+
}
|
|
276
|
+
catch {
|
|
277
|
+
/* fall through to bundled */
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
const here = thisDir();
|
|
281
|
+
const candidates = [
|
|
282
|
+
join(here, '..', 'prompts', MECHANISMS_PROMPT_FILENAME),
|
|
283
|
+
join(here, '..', '..', 'prompts', MECHANISMS_PROMPT_FILENAME),
|
|
284
|
+
];
|
|
285
|
+
for (const path of candidates) {
|
|
286
|
+
try {
|
|
287
|
+
return await readFile(path, 'utf-8');
|
|
288
|
+
}
|
|
289
|
+
catch {
|
|
290
|
+
/* try next */
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
throw new Error(`mechanisms guide not found. Tried: ${candidates.join(', ')}`);
|
|
294
|
+
}
|
|
230
295
|
async function fetchIntegrationSuccess() {
|
|
231
296
|
const here = thisDir();
|
|
232
297
|
const candidates = [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guide.command.js","sourceRoot":"","sources":["../../src/commands/guide.command.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"guide.command.js","sourceRoot":"","sources":["../../src/commands/guide.command.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { Command } from 'commander';
|
|
2
|
+
/** The seven TBP-540 decision domains a journey can open with. */
|
|
3
|
+
export type DecisionDomain = 'login' | 'teams' | 'roles' | 'payments' | 'feature-control' | 'look-and-feel' | 'going-live';
|
|
4
|
+
export type Master = 'auth' | 'billing' | 'flags';
|
|
5
|
+
export interface Journey {
|
|
6
|
+
name: string;
|
|
7
|
+
title: string;
|
|
8
|
+
domain: DecisionDomain | null;
|
|
9
|
+
master: Master | null;
|
|
10
|
+
/** Per-framework guide feature; `auth` resolves to `sdk-auth` on the frontends via guide coverage. */
|
|
11
|
+
feature: 'auth' | 'billing' | 'feature-flags' | 'team' | null;
|
|
12
|
+
steps: string[];
|
|
13
|
+
}
|
|
14
|
+
export declare const JOURNEYS: Journey[];
|
|
15
|
+
export declare function findJourney(name: string): Journey | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* THE seam for TBP-540: a decision guide is `prompts/decisions/<domain>.md`,
|
|
18
|
+
* beside the masters. Read like them (dev override, then bundled), then from
|
|
19
|
+
* GitHub so a CLI released before a guide was written still finds it — the
|
|
20
|
+
* same path the MCP server reads. Null means not written yet.
|
|
21
|
+
*/
|
|
22
|
+
export declare function fetchDecisionGuide(domain: DecisionDomain): Promise<string | null>;
|
|
23
|
+
/** The pieces a journey is built from, injected so the composition is testable without a network. */
|
|
24
|
+
export interface JourneySources {
|
|
25
|
+
decision: (domain: DecisionDomain) => Promise<string | null>;
|
|
26
|
+
master: (master: Master) => Promise<string>;
|
|
27
|
+
frameworkGuide: (framework: string, feature: string) => Promise<string>;
|
|
28
|
+
/** Which feature stems exist per framework (guide-coverage.json). */
|
|
29
|
+
coverage: () => Record<string, string[]>;
|
|
30
|
+
}
|
|
31
|
+
export interface ComposedJourney {
|
|
32
|
+
journey: string;
|
|
33
|
+
framework: string | null;
|
|
34
|
+
/** 'decision' once TBP-540's guide exists; 'master' or 'none' until then. */
|
|
35
|
+
opensWith: 'decision' | 'master' | 'none';
|
|
36
|
+
guide: string;
|
|
37
|
+
}
|
|
38
|
+
export declare function composeJourney(journey: Journey, framework: string | null, sources: JourneySources): Promise<ComposedJourney>;
|
|
39
|
+
/** The message for `bridge guide <name>` when nothing matches: names what does. */
|
|
40
|
+
export declare function unknownGuideMessage(name: string, frameworks: string[]): string;
|
|
41
|
+
export declare function registerJourneyCommands(guide: Command, sources: JourneySources, detectFramework: (override: string | undefined, cwd: string) => Promise<string | undefined>): void;
|
|
42
|
+
//# sourceMappingURL=journeys.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"journeys.d.ts","sourceRoot":"","sources":["../../src/commands/journeys.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiBzC,kEAAkE;AAClE,MAAM,MAAM,cAAc,GACtB,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,UAAU,GAAG,iBAAiB,GAAG,eAAe,GAAG,YAAY,CAAC;AAElG,MAAM,MAAM,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;AAElD,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,cAAc,GAAG,IAAI,CAAC;IAC9B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,sGAAsG;IACtG,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,eAAe,GAAG,MAAM,GAAG,IAAI,CAAC;IAC9D,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAMD,eAAO,MAAM,QAAQ,EAAE,OAAO,EA6F7B,CAAC;AAEF,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAE7D;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAqBvF;AAED,qGAAqG;AACrG,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,CAAC,MAAM,EAAE,cAAc,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC7D,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5C,cAAc,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACxE,qEAAqE;IACrE,QAAQ,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CAC1C;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,6EAA6E;IAC7E,SAAS,EAAE,UAAU,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC1C,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAsB,cAAc,CAClC,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,eAAe,CAAC,CAyC1B;AAED,mFAAmF;AACnF,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM,CAM9E;AAED,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,cAAc,EACvB,eAAe,EAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,GAC1F,IAAI,CAyBN"}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { commandsDir } from './runtime-dir.js';
|
|
4
|
+
import { outputError, outputPrompt, outputSuccess } from '../output.js';
|
|
5
|
+
import { cliPromptUrl } from '../prompt-urls.js';
|
|
6
|
+
const PRODUCT_QUESTIONS = 'Product questions (what to charge, who may do what, what a plan includes, what users see) belong to the ' +
|
|
7
|
+
'developer: ask them and wait. Mechanics you decide, following the guide, and state the reason in one line.';
|
|
8
|
+
export const JOURNEYS = [
|
|
9
|
+
{
|
|
10
|
+
name: 'add-login',
|
|
11
|
+
title: 'Add login',
|
|
12
|
+
domain: 'login',
|
|
13
|
+
master: 'auth',
|
|
14
|
+
feature: 'auth',
|
|
15
|
+
steps: [
|
|
16
|
+
'Goal: users can sign up and sign in to this app through the Bridge.',
|
|
17
|
+
'Read the current setup with `bridge app get` and `bridge auth config`.',
|
|
18
|
+
'Ask the developer which sign-in methods they want before changing them; SSO is `bridge setup sso`.',
|
|
19
|
+
'Register the callback URL with `bridge app redirect-uris add` (never replace the list).',
|
|
20
|
+
'Prove it works at the end: `bridge test-user create`, then `bridge test-user verify`.',
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
name: 'add-paid-plan',
|
|
25
|
+
title: 'Add a paid plan',
|
|
26
|
+
domain: 'payments',
|
|
27
|
+
master: 'billing',
|
|
28
|
+
feature: 'billing',
|
|
29
|
+
steps: [
|
|
30
|
+
'Goal: a customer can pick a paid plan and pay for it.',
|
|
31
|
+
'Read the current plans with `bridge plan list`.',
|
|
32
|
+
'Plan names, prices, trials and quotas are product decisions: ask the developer, then `bridge plan create`, `bridge plan price set`, `bridge plan quota set`.',
|
|
33
|
+
'Check payments with `bridge stripe status`; `bridge stripe connect` if it is not connected.',
|
|
34
|
+
'A /welcome page for new customers is an offer: suggest it, and create it only if the developer says yes.',
|
|
35
|
+
],
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: 'add-feature-flag',
|
|
39
|
+
title: 'Add a feature flag',
|
|
40
|
+
domain: 'feature-control',
|
|
41
|
+
master: 'flags',
|
|
42
|
+
feature: 'feature-flags',
|
|
43
|
+
steps: [
|
|
44
|
+
'Goal: a feature in the app is controlled by a Bridge flag.',
|
|
45
|
+
'Read the current flags with `bridge flag list`.',
|
|
46
|
+
'Who should see the feature is the developer\'s call: ask, then `bridge flag create` with that rule.',
|
|
47
|
+
'Read the flag in the app with the SDK surface the guide names, never by hand against SDK internals.',
|
|
48
|
+
],
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: 'add-teams',
|
|
52
|
+
title: 'Add teams',
|
|
53
|
+
domain: 'teams',
|
|
54
|
+
master: null,
|
|
55
|
+
feature: 'team',
|
|
56
|
+
steps: [
|
|
57
|
+
'Goal: a customer can invite teammates into their workspace, each with a role.',
|
|
58
|
+
'Read the current roles with `bridge role list`.',
|
|
59
|
+
'Which roles exist and what each may do are product decisions: ask the developer, then `bridge role create` / `bridge role update`.',
|
|
60
|
+
'Wire the team UI with the SDK surface the per-framework team guide names.',
|
|
61
|
+
],
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
name: 'go-live',
|
|
65
|
+
title: 'Go live',
|
|
66
|
+
domain: 'going-live',
|
|
67
|
+
master: null,
|
|
68
|
+
feature: null,
|
|
69
|
+
steps: [
|
|
70
|
+
'Goal: nothing on the readiness checklist blocks real users.',
|
|
71
|
+
'Run `bridge setup status` and start from its productionNeeds. Take each item in turn with the developer: production URLs, redirect URIs and origins, the email sender (`bridge setup communication`), live Stripe keys.',
|
|
72
|
+
'Finish with `bridge setup status` again and show the developer what is left.',
|
|
73
|
+
],
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
name: 'verify-setup',
|
|
77
|
+
title: 'Verify setup',
|
|
78
|
+
domain: null,
|
|
79
|
+
master: null,
|
|
80
|
+
feature: null,
|
|
81
|
+
steps: [
|
|
82
|
+
'Goal: evidence that sign-in works end to end, not an opinion.',
|
|
83
|
+
'1. `bridge diagnose` in the project: it reads the .env files and reports every difference with its fix.',
|
|
84
|
+
'2. `bridge setup status` for the readiness checklist.',
|
|
85
|
+
'3. `bridge test-user create`, then `bridge test-user verify` with its email and password.',
|
|
86
|
+
],
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
name: 'whats-wrong',
|
|
90
|
+
title: 'What is wrong',
|
|
91
|
+
domain: null,
|
|
92
|
+
master: null,
|
|
93
|
+
feature: null,
|
|
94
|
+
steps: [
|
|
95
|
+
'Goal: the reason for the failure and its fix, from evidence.',
|
|
96
|
+
'Someone cannot sign in: `bridge event auth-attempts` for their email; each failed attempt carries its reason and fix.',
|
|
97
|
+
'The app itself misbehaves: `bridge diagnose` in the project, then `bridge setup status`.',
|
|
98
|
+
'To tell a Bridge problem from an app-code problem: `bridge test-user create` and `bridge test-user verify`. If that works, the app code is the difference.',
|
|
99
|
+
],
|
|
100
|
+
},
|
|
101
|
+
];
|
|
102
|
+
export function findJourney(name) {
|
|
103
|
+
return JOURNEYS.find((j) => j.name === name);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* THE seam for TBP-540: a decision guide is `prompts/decisions/<domain>.md`,
|
|
107
|
+
* beside the masters. Read like them (dev override, then bundled), then from
|
|
108
|
+
* GitHub so a CLI released before a guide was written still finds it — the
|
|
109
|
+
* same path the MCP server reads. Null means not written yet.
|
|
110
|
+
*/
|
|
111
|
+
export async function fetchDecisionGuide(domain) {
|
|
112
|
+
const filename = `${domain}.md`;
|
|
113
|
+
const localDir = process.env.BRIDGE_GUIDE_LOCAL_DIR;
|
|
114
|
+
const candidates = [
|
|
115
|
+
...(localDir ? [join(localDir, 'bridge-cli', 'bridge-cli', 'prompts', 'decisions', filename)] : []),
|
|
116
|
+
join(commandsDir, '..', 'prompts', 'decisions', filename),
|
|
117
|
+
join(commandsDir, '..', '..', 'prompts', 'decisions', filename),
|
|
118
|
+
];
|
|
119
|
+
for (const path of candidates) {
|
|
120
|
+
try {
|
|
121
|
+
return await readFile(path, 'utf-8');
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
/* try next */
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
try {
|
|
128
|
+
const res = await fetch(cliPromptUrl('decisions', filename));
|
|
129
|
+
return res.ok ? await res.text() : null;
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
export async function composeJourney(journey, framework, sources) {
|
|
136
|
+
const header = [`# ${journey.title} — a Bridge journey`, '', ...journey.steps, '', PRODUCT_QUESTIONS, ''];
|
|
137
|
+
if (journey.feature) {
|
|
138
|
+
header.push(framework
|
|
139
|
+
? `Framework: ${framework}.`
|
|
140
|
+
: 'Framework not detected from package.json: re-run with `--framework <name>` ' +
|
|
141
|
+
'(svelte, react, angular, nextjs, nestjs, express) to include the per-framework guide, or ask the developer.');
|
|
142
|
+
}
|
|
143
|
+
header.push(`In an MCP client the same journey is the \`${journey.name}\` prompt of the Bridge server.`);
|
|
144
|
+
const sections = [header.join('\n')];
|
|
145
|
+
let opensWith = 'none';
|
|
146
|
+
if (journey.domain) {
|
|
147
|
+
const decision = await sources.decision(journey.domain);
|
|
148
|
+
if (decision) {
|
|
149
|
+
sections.push(decision);
|
|
150
|
+
opensWith = 'decision';
|
|
151
|
+
}
|
|
152
|
+
else if (journey.master) {
|
|
153
|
+
sections.push(`(The decision guide for ${journey.domain} is not written yet; this is the closest existing guide.)\n\n` +
|
|
154
|
+
(await sources.master(journey.master)));
|
|
155
|
+
opensWith = 'master';
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
sections.push(`(The decision guide for ${journey.domain} is not written yet, and no framework-agnostic guide covers it. ` +
|
|
159
|
+
'Work from the steps above, and take every product decision to the developer.)');
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (journey.feature && framework) {
|
|
163
|
+
const features = sources.coverage()[framework] ?? [];
|
|
164
|
+
const feature = journey.feature === 'auth' && features.includes('sdk-auth') ? 'sdk-auth' : journey.feature;
|
|
165
|
+
sections.push(await sources.frameworkGuide(framework, feature));
|
|
166
|
+
}
|
|
167
|
+
return { journey: journey.name, framework, opensWith, guide: sections.join('\n\n---\n\n') };
|
|
168
|
+
}
|
|
169
|
+
/** The message for `bridge guide <name>` when nothing matches: names what does. */
|
|
170
|
+
export function unknownGuideMessage(name, frameworks) {
|
|
171
|
+
return (`No guide named '${name}'. Journeys: ${JOURNEYS.map((j) => j.name).join(', ')}. ` +
|
|
172
|
+
`Frameworks: ${frameworks.join(', ')} (e.g. \`bridge guide svelte auth\`). ` +
|
|
173
|
+
'Also: flags, billing, mechanisms, custom, list. `bridge guide` alone prints the integration master.');
|
|
174
|
+
}
|
|
175
|
+
export function registerJourneyCommands(guide, sources, detectFramework) {
|
|
176
|
+
for (const journey of JOURNEYS) {
|
|
177
|
+
const cmd = guide
|
|
178
|
+
.command(journey.name)
|
|
179
|
+
.description(`Journey: ${journey.title.toLowerCase()} (the same as the Bridge MCP prompt)`)
|
|
180
|
+
.option('--json', 'Emit a JSON envelope instead of the raw markdown prompt');
|
|
181
|
+
if (journey.feature) {
|
|
182
|
+
cmd
|
|
183
|
+
.option('--framework <name>', 'svelte | react | angular | nextjs | nestjs | express (auto-detected from package.json when omitted)')
|
|
184
|
+
.option('--cwd <path>', 'Project dir used for framework detection', process.cwd());
|
|
185
|
+
}
|
|
186
|
+
cmd.action(async (_opts, command) => {
|
|
187
|
+
try {
|
|
188
|
+
const opts = command.optsWithGlobals();
|
|
189
|
+
const framework = journey.feature
|
|
190
|
+
? (await detectFramework(opts.framework, opts.cwd ?? process.cwd())) ?? null
|
|
191
|
+
: null;
|
|
192
|
+
const composed = await composeJourney(journey, framework, sources);
|
|
193
|
+
if (opts.json)
|
|
194
|
+
outputSuccess(composed);
|
|
195
|
+
else
|
|
196
|
+
outputPrompt(composed.guide);
|
|
197
|
+
}
|
|
198
|
+
catch (err) {
|
|
199
|
+
outputError(err);
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
//# sourceMappingURL=journeys.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"journeys.js","sourceRoot":"","sources":["../../src/commands/journeys.ts"],"names":[],"mappings":"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"}
|
|
@@ -90,12 +90,12 @@ bridge guide <framework> # hosted-auth audit checklist
|
|
|
90
90
|
bridge guide <framework> sdk-auth # SDK-auth audit checklist (in-app forms)
|
|
91
91
|
```
|
|
92
92
|
|
|
93
|
-
The framework guide tells you precisely what must exist (bootstrap call, provider wrapping,
|
|
93
|
+
The framework guide tells you precisely what must exist (bootstrap call, provider wrapping, the auth pages, environment variables). Apply that checklist to the project on disk.
|
|
94
94
|
|
|
95
95
|
**General decision matrix** (independent of framework):
|
|
96
96
|
|
|
97
|
-
- **Wiring complete AND
|
|
98
|
-
- **Bootstrap wiring complete BUT auth
|
|
97
|
+
- **Wiring complete AND the auth pages are served** → Bridge is fully integrated. Skip to **Step 6b** and output the success message.
|
|
98
|
+
- **Bootstrap wiring complete BUT the auth pages are missing** → Bridge is partially integrated. Without them signup verification, password reset and the SSO callback land on a 404. On SvelteKit the fix is one file, `src/routes/auth/[...bridge]/+page.svelte` rendering `<BridgeAuthRoutes />`; hand-written pages that only render a Bridge component can then be deleted. On other frameworks the guide names the files. Add only what's missing.
|
|
99
99
|
- **Bootstrap wiring incomplete** (regardless of route state) → Offer to complete the initial setup (proceed to Step 4).
|
|
100
100
|
- **Bridge is NOT installed** → Continue with Steps 2–6 for fresh setup.
|
|
101
101
|
|
|
@@ -193,9 +193,11 @@ For each confirmed project, fetch the framework-specific integration prompt.
|
|
|
193
193
|
| Express | `bridge guide express` |
|
|
194
194
|
|
|
195
195
|
Follow the per-framework guide instructions verbatim. Pass these values from Step 3:
|
|
196
|
-
- `appId` — same for all projects
|
|
196
|
+
- `appId` — same for all projects; it goes in the project's `.env` (`VITE_BRIDGE_APP_ID` on SvelteKit, `BRIDGE_APP_ID` on NestJS), which the plugin reads itself
|
|
197
197
|
- `packageManager` — detected in Step 1 (use it for all install commands)
|
|
198
198
|
|
|
199
|
+
**What the handover looks like.** The guides are short because the plugins serve their own pages. On SvelteKit the whole frontend integration is the `.env` line, `src/routes/+layout.ts` (`export const load = bridgeBootstrap({ rules })`), `src/routes/+layout.svelte` (`<BridgeBootstrap>`) and one auth file, `src/routes/auth/[...bridge]/+page.svelte` — about fifteen lines. On NestJS it is `BridgeModule.forRoot({ guard: { global: true } })` in `AppModule` and the `.env` line. Do not write login, signup, callback or password pages by hand, and no fetch helper for tokens. `bridge guide mechanisms` explains the levels and customisation rungs if the developer asks for more.
|
|
200
|
+
|
|
199
201
|
**Order:** Frontend first, then backend. This lets you verify login works before adding backend guards.
|
|
200
202
|
|
|
201
203
|
## Step 5 — Route protection defaults
|
|
@@ -248,6 +250,6 @@ After delivering the message, the integration is complete.
|
|
|
248
250
|
After auth is wired and the success banner is printed, the developer commonly wants flags and billing next. Mention these one-liners so they know how to continue:
|
|
249
251
|
|
|
250
252
|
- **Feature Flags 2.0** → `bridge guide flags` (auto-detects framework, sets up flag evaluation, telemetry, realtime)
|
|
251
|
-
- **Billing 2.0** → `bridge guide billing` (
|
|
253
|
+
- **Billing 2.0** → `bridge guide billing` (plans, the subscription pages, the paywall, plan limits enforced by the backend)
|
|
252
254
|
|
|
253
255
|
Do not run them automatically — the developer decides when they want each track.
|
|
@@ -29,7 +29,7 @@ Scan the current directory and its immediate subdirectories for `package.json` f
|
|
|
29
29
|
|
|
30
30
|
3. **Bridge Auth installed?** — look for `@nebulr-group/bridge-<framework>` in dependencies. Billing is scoped to a workspace/tenant and requires Bridge Auth. If not present, stop and run `bridge guide` first.
|
|
31
31
|
|
|
32
|
-
4. **Billing already wired?** — check whether
|
|
32
|
+
4. **Billing already wired?** — check whether the subscription pages are served (on SvelteKit: `src/routes/subscription/[...bridge]/+page.svelte` rendering `<BridgeBillingRoutes />`) and whether `bridge plan list` returns at least one plan. If billing looks complete, jump to **Step 1b**.
|
|
33
33
|
|
|
34
34
|
5. **Existing billing system?** — look for `stripe`, `@stripe/*`, `paddle-*`, `lemon-squeezy`, `chargebee`. Flag any found.
|
|
35
35
|
|
|
@@ -38,11 +38,12 @@ Scan the current directory and its immediate subdirectories for `package.json` f
|
|
|
38
38
|
If Step 1 found billing already partially or fully set up, audit it before doing anything:
|
|
39
39
|
|
|
40
40
|
- Run `bridge plan list` — are plans defined?
|
|
41
|
-
- Check
|
|
41
|
+
- Check the subscription pages are served (SvelteKit: the `subscription/[...bridge]` file above; other frameworks: the route the per-framework guide names)
|
|
42
42
|
- Check the root layout for `<BridgeBillingNotice />`
|
|
43
|
+
- Check every backend handler that creates a limited thing carries the plan-limit decorator (NestJS: `@RequireQuota`)
|
|
43
44
|
|
|
44
45
|
**Decision:**
|
|
45
|
-
- **Fully wired** (plans exist,
|
|
46
|
+
- **Fully wired** (plans exist, subscription pages served, notice in layout, limits on the backend) → skip to **Step 6** and output the success message
|
|
46
47
|
- **Partially wired** → tell the user exactly what's missing and only add what's absent
|
|
47
48
|
- **Plans missing** → continue from Step 3 (pricing model)
|
|
48
49
|
|
|
@@ -92,13 +93,16 @@ From their answer, map everything to confirmation tables before creating anythin
|
|
|
92
93
|
|
|
93
94
|
**Quotas** (per-resource limits that differ between plans):
|
|
94
95
|
|
|
95
|
-
| plan | metric | limit | policy |
|
|
96
|
-
|
|
97
|
-
| `free` | `ai_completions` | 100 | hard |
|
|
98
|
-
| `pro` | `ai_completions` | 1000 | hard |
|
|
96
|
+
| plan | metric | limit | policy | kind |
|
|
97
|
+
|------|--------|-------|--------|------|
|
|
98
|
+
| `free` | `ai_completions` | 100 | hard | counter |
|
|
99
|
+
| `pro` | `ai_completions` | 1000 | hard | counter |
|
|
100
|
+
| `free` | `projects` | 3 | hard | gauge |
|
|
99
101
|
|
|
100
102
|
Use `hard` when overage should be blocked. Use `metered` when overage should bill via Stripe.
|
|
101
103
|
|
|
104
|
+
**Counter or gauge?** If deleting it frees room, it's a gauge and your app counts it; if it happened, it's a counter and Bridge counts it. AI completions, exports and API calls are counters (reset each period); projects, tickets and seats (`users`) are gauges (never reset). The developer decides the metric list; you decide the kind from that sentence and say why in one line.
|
|
105
|
+
|
|
102
106
|
**Entitlements** (features on for some plans, off for others):
|
|
103
107
|
|
|
104
108
|
| plan | key | value |
|
|
@@ -106,6 +110,8 @@ Use `hard` when overage should be blocked. Use `metered` when overage should bil
|
|
|
106
110
|
| `free` | `advanced_analytics` | off |
|
|
107
111
|
| `pro` | `advanced_analytics` | on |
|
|
108
112
|
|
|
113
|
+
An entitlement is not configured on its own: every `hard` quota with a limit above 0 is also an entitlement of the same name. A feature that is on for `pro` is therefore a hard quota on `pro` (e.g. `--metric advanced_analytics --limit 1 --policy hard`) that nothing counts, and absent from `free`; the backend gates it with `@RequireEntitlement('advanced_analytics')`, never with `@RequireQuota`.
|
|
114
|
+
|
|
109
115
|
If there are no per-plan limits or feature differences, the quotas and entitlements tables are empty — skip those commands below.
|
|
110
116
|
|
|
111
117
|
**Do not create anything until the developer confirms all tables.**
|
|
@@ -152,9 +158,12 @@ feature at the cap (entitlement flips off); a `metered` quota bills overage per
|
|
|
152
158
|
unit and never blocks — it requires a per-unit price:
|
|
153
159
|
|
|
154
160
|
```bash
|
|
155
|
-
# Hard cap (block at the limit)
|
|
161
|
+
# Hard cap (block at the limit) — a counter, the default
|
|
156
162
|
bridge plan quota set <plan> --metric <key> --limit <n> --policy hard
|
|
157
163
|
|
|
164
|
+
# Hard cap on something that exists (a gauge: projects, tickets)
|
|
165
|
+
bridge plan quota set <plan> --metric <key> --limit <n> --policy hard --kind gauge
|
|
166
|
+
|
|
158
167
|
# Metered: first <limit> units free, then --price-amount per unit (limit 0 = pure
|
|
159
168
|
# per-unit, billed from unit 1). Currency defaults to the plan's price currency.
|
|
160
169
|
bridge plan quota set <plan> --metric <key> --limit <n> --policy metered --price-amount <perUnit> [--price-currency <cur>]
|
|
@@ -162,6 +171,9 @@ bridge plan quota set <plan> --metric <key> --limit <n> --policy metered --price
|
|
|
162
171
|
|
|
163
172
|
Run one command per row. (There is no `plan entitlement set` command —
|
|
164
173
|
entitlements are derived from `hard` quotas automatically; do not invent one.)
|
|
174
|
+
Check the result with `bridge plan quota list`, which lists every metric with its kind.
|
|
175
|
+
|
|
176
|
+
**Where the limit is enforced.** A quota is only a number until the backend enforces it: the plan-limit decorator on the handler that creates the thing (NestJS `@RequireQuota`) refuses at the cap and records the use after a successful request — a POST increments the limit, nothing else to wire. The frontend only shows that decision; a frontend-only app cannot enforce a limit. `bridge guide mechanisms` has the whole model.
|
|
165
177
|
|
|
166
178
|
## Step 4 — Fetch and apply the per-framework guide
|
|
167
179
|
|
|
@@ -193,6 +205,7 @@ opts out** — it's the expected first-run experience.
|
|
|
193
205
|
- The per-framework guide (Step 4) mounts the plugin's subscription pages, which include a
|
|
194
206
|
default paywall page (on SvelteKit: `/subscription/plan`, served by the subscription
|
|
195
207
|
catch-all). Confirm that part ran. Do **not** create a separate welcome page on your own.
|
|
208
|
+
- The paywall applies once the app has plans; `paymentsAutoRedirect` (below) switches it.
|
|
196
209
|
- A dedicated onboarding page such as `/welcome` is a product choice: **ask the developer**
|
|
197
210
|
whether they want one. Only if they say yes, add it as the per-framework guide shows and
|
|
198
211
|
point `billing.paywallRoute` at it.
|
|
@@ -205,8 +218,8 @@ If the developer does **not** want a forced paywall, disable it with one command
|
|
|
205
218
|
bridge app update --payments-auto-redirect false
|
|
206
219
|
```
|
|
207
220
|
|
|
208
|
-
With the paywall off, users can enter the app without choosing a plan;
|
|
209
|
-
|
|
221
|
+
With the paywall off, users can enter the app without choosing a plan; the subscription pages
|
|
222
|
+
still work for self-serve upgrades.
|
|
210
223
|
|
|
211
224
|
## Step 5 — Verify
|
|
212
225
|
|
|
@@ -219,6 +232,7 @@ For each integrated project, the agent verifies — do not hand this to the deve
|
|
|
219
232
|
5. Complete a test payment — redirected back with the updated plan showing
|
|
220
233
|
6. Cancel a payment — redirected back to the subscription page
|
|
221
234
|
7. Paywall (unless opted out): sign in as a new tenant with no plan — you land on the paywall page (or `/welcome` if the developer chose one) and can't reach the app until a plan is chosen
|
|
235
|
+
8. Plan limit (when a backend was wired): at the cap, the decorated request answers `402 QUOTA_EXCEEDED` — send it with curl, not only through the UI — and in the app the upgrade dialog opens naming the metric
|
|
222
236
|
|
|
223
237
|
If anything fails, diagnose and fix before moving on.
|
|
224
238
|
|
|
@@ -238,7 +252,7 @@ If anything fails, diagnose and fix before moving on.
|
|
|
238
252
|
Billing is live in [project-name].
|
|
239
253
|
|
|
240
254
|
✅ Plans — [plan-names]
|
|
241
|
-
✅
|
|
255
|
+
✅ Subscription page — [subscription-route]
|
|
242
256
|
✅ Paywall — [paywall-summary]
|
|
243
257
|
✅ Lifecycle notices — auto-render on trial / payment failure / cancel
|
|
244
258
|
✅ Quotas and entitlements — [quota-summary]
|
|
@@ -258,18 +272,18 @@ If anything fails, diagnose and fix before moving on.
|
|
|
258
272
|
Fill every `[placeholder]` with real values from the integration:
|
|
259
273
|
- `[project-name]` — folder name and/or `package.json` name
|
|
260
274
|
- `[plan-names]` — the plan keys (e.g. `free`, `premium`)
|
|
261
|
-
- `[
|
|
275
|
+
- `[subscription-route]` — where the subscription page is served (SvelteKit default `/subscription`)
|
|
262
276
|
- `[paywall-summary]` — e.g. "new users sent to `/subscription/plan` to pick a plan" (or "off — `paymentsAutoRedirect false`")
|
|
263
|
-
- `[quota-summary]` — metric keys and
|
|
277
|
+
- `[quota-summary]` — metric keys, limits and kind, and the backend handlers that enforce them, or "none"
|
|
264
278
|
- `[what-i-actually-did]` / `[what-i-changed]` — every file created or modified, every command run
|
|
265
279
|
|
|
266
280
|
## Step 7 — Offer follow-on tracks
|
|
267
281
|
|
|
268
282
|
After the success banner, mention what they can add next:
|
|
269
283
|
|
|
270
|
-
- **
|
|
271
|
-
- **
|
|
272
|
-
- **Portal** —
|
|
284
|
+
- **Plan limits on the backend** — if the backend was not wired in this session: `bridge guide billing --framework nestjs` (one decorator per handler)
|
|
285
|
+
- **Limits in the UI** — an upgrade dialog opens on its own when the backend refuses; disabling a button before the click or showing usage numbers is in the frontend guide, Step 3
|
|
286
|
+
- **Portal** — "Manage billing" is already on the subscription page; the per-framework guide shows how to place it elsewhere
|
|
273
287
|
|
|
274
288
|
Do not run these automatically — the developer decides when they want each.
|
|
275
289
|
|
|
@@ -282,4 +296,4 @@ Do not run these automatically — the developer decides when they want each.
|
|
|
282
296
|
| `hard` | Entitlement flips off at cap; no overage | Seat counts, included features |
|
|
283
297
|
| `metered` | Overage bills as a Stripe metered price; usage continues | API calls, storage |
|
|
284
298
|
|
|
285
|
-
|
|
299
|
+
Bridge's usage ingest always accepts events — it never refuses on the app's behalf. The refusal at a hard cap comes from **your** backend: the plan-limit decorator (`@RequireQuota`) reads the quota and answers `402 QUOTA_EXCEEDED` before the handler runs. `bridge guide mechanisms` explains the model.
|
|
@@ -19,7 +19,7 @@ Each plugin repo owns its own framework-specific prompt under `mcp/feature-flags
|
|
|
19
19
|
|
|
20
20
|
`bridge guide <framework> flags` is an equivalent route — both call the same plugin-repo prompt.
|
|
21
21
|
|
|
22
|
-
If the CLI returns `HTTP 404 — file may not exist yet in the plugin repo`, the plugin hasn't published its
|
|
22
|
+
If the CLI returns `HTTP 404 — file may not exist yet in the plugin repo`, the plugin hasn't published its flags guide yet. Tell the user that's the blocker and fall back to `@nebulr-group/bridge-auth-core` directly (it's framework-agnostic and stable). Do NOT improvise an inline integration in this master prompt — the plugin guide is the canonical handover.
|
|
23
23
|
|
|
24
24
|
## Step 0 — Authenticate
|
|
25
25
|
|
|
@@ -63,7 +63,7 @@ Track as you work:
|
|
|
63
63
|
|
|
64
64
|
## Mental model (1-minute version)
|
|
65
65
|
|
|
66
|
-
A flag
|
|
66
|
+
A flag has:
|
|
67
67
|
|
|
68
68
|
| Field | Possible values |
|
|
69
69
|
|---|---|
|
|
@@ -75,7 +75,7 @@ A flag in has:
|
|
|
75
75
|
|
|
76
76
|
Branches are first-match-wins; conditions within a branch AND together; `rolloutPct` is rule-level (0-100) and requires `identity` on the eval context.
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
Every plugin wraps the same evaluation, and the return type is inferred from the default value, so no casts. On SvelteKit it is `useFlag(key, defaultValue)` in script and `<FeatureFlag key defaultValue>` in markup, both from `@nebulr-group/bridge-svelte/flags`; a whole route is gated by a `featureFlag` rule in `bridgeBootstrap()`.
|
|
79
79
|
|
|
80
80
|
## Step 1 — Discover projects
|
|
81
81
|
|
|
@@ -95,7 +95,7 @@ Scan the current directory and its immediate subdirectories for `package.json` f
|
|
|
95
95
|
- `@nestjs/core` → **NestJS** (backend)
|
|
96
96
|
- `express` (without `@nestjs/core`) → **Express** (backend)
|
|
97
97
|
|
|
98
|
-
3. **Existing Bridge plugin?** Check for `@nebulr-group/bridge-<framework>` — if present, the project may already have auth or other Bridge surfaces. Flags can co-exist with auth in the same plugin; the per-framework guide will tell you whether
|
|
98
|
+
3. **Existing Bridge plugin?** Check for `@nebulr-group/bridge-<framework>` — if present, the project may already have auth or other Bridge surfaces. Flags can co-exist with auth in the same plugin; the per-framework guide will tell you whether its bootstrap is already in place. On SvelteKit, an app that already calls `bridgeBootstrap()` and renders `<BridgeBootstrap>` has flags running — there is nothing to install or initialise.
|
|
99
99
|
|
|
100
100
|
4. **Existing flag system?** Look for `launchdarkly-*`, `@unleash/*`, `posthog-js`, `growthbook-*` — warn the user that Bridge flags will run in parallel unless they migrate.
|
|
101
101
|
|
|
@@ -167,8 +167,8 @@ Where `<name>` is one of: `svelte`, `react`, `nextjs`, `angular`, `nestjs`, `exp
|
|
|
167
167
|
|
|
168
168
|
**Every per-framework guide covers this contract:**
|
|
169
169
|
|
|
170
|
-
- **Install** — the right package + version + import path (
|
|
171
|
-
- **Bootstrap** — provider / module / factory setup,
|
|
170
|
+
- **Install** — the right package + version + import path (when the plugin is already installed for auth, nothing more to install)
|
|
171
|
+
- **Bootstrap** — provider / module / factory setup where the framework needs one (SvelteKit with Bridge Auth needs none: `<BridgeBootstrap>` starts flags, reading the app id from `.env`)
|
|
172
172
|
- **Eval context** — idiomatic placement for `identity` and `attributes`, including how to wire the `identitySource` chosen in Step 2
|
|
173
173
|
- **Reading a flag** — the framework wrapper (`useFlag`, `FeatureFlag`, `signal`, decorator) and the synchronous `evaluateFlag` for non-reactive contexts
|
|
174
174
|
- **Advanced attribute wiring** — the unified `bridge.attributes` write surface and realtime event subscription via `bridge.events.handle`
|
|
@@ -177,14 +177,14 @@ Where `<name>` is one of: `svelte`, `react`, `nextjs`, `angular`, `nestjs`, `exp
|
|
|
177
177
|
|
|
178
178
|
**Pass these values from this master to the per-framework prompt:**
|
|
179
179
|
- `appId` — from Step 3
|
|
180
|
-
- `baseUrl` —
|
|
180
|
+
- `baseUrl` — production by default; a stage, local or self-hosted app must set it (SvelteKit reads `VITE_BRIDGE_API_BASE_URL` itself)
|
|
181
181
|
- `packageManager` — from Step 1
|
|
182
182
|
- `mode` — `frontend` (browser projects) or `backend` (NestJS, Express, Next.js server)
|
|
183
183
|
- `identitySource` — from Step 2
|
|
184
184
|
|
|
185
185
|
**Order:** Frontend first, then backend.
|
|
186
186
|
|
|
187
|
-
If the CLI returns `HTTP 404`, the plugin hasn't published its
|
|
187
|
+
If the CLI returns `HTTP 404`, the plugin hasn't published its flags guide yet. Tell the user that's the blocker and fall back to `@nebulr-group/bridge-auth-core` directly — `new BridgeFlags({ appId, baseUrl, mode })` + `bridge.setContext({...})` + `bridge.flag(...)`. The SDK shape is identical across frameworks; only the bindings differ.
|
|
188
188
|
|
|
189
189
|
## Step 5 — Verify
|
|
190
190
|
|
|
@@ -94,14 +94,13 @@ PLACEHOLDER: what-i-changed
|
|
|
94
94
|
|
|
95
95
|
Frontend (my-saas-app):
|
|
96
96
|
✅ @nebulr-group/bridge-svelte installed
|
|
97
|
-
✅ src/routes/+layout.ts
|
|
98
|
-
✅ src/routes/+layout.svelte
|
|
99
|
-
✅
|
|
97
|
+
✅ src/routes/+layout.ts — export const load = bridgeBootstrap({ rules })
|
|
98
|
+
✅ src/routes/+layout.svelte — app wrapped in <BridgeBootstrap>
|
|
99
|
+
✅ src/routes/auth/[...bridge]/+page.svelte — <BridgeAuthRoutes /> serves every sign-in page
|
|
100
100
|
✅ .env configured with VITE_BRIDGE_APP_ID=abc123
|
|
101
101
|
✅ Bridge app configured for http://localhost:5175
|
|
102
102
|
|
|
103
103
|
Backend (my-saas-api):
|
|
104
104
|
✅ @nebulr-group/bridge-nestjs installed
|
|
105
|
-
✅ BridgeModule
|
|
106
|
-
✅ Global JWT guard applied
|
|
105
|
+
✅ AppModule — BridgeModule.forRoot({ guard: { global: true } }), every route needs a signed-in user
|
|
107
106
|
✅ .env configured with BRIDGE_APP_ID=abc123
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
# How Bridge works — the mechanisms and the levels
|
|
2
|
+
|
|
3
|
+
One page for the rules every Bridge guide builds on. Read it before you write code against a limit, an upgrade prompt or a restyled sign-in page. The per-framework guides (`bridge guide svelte`, `bridge guide nestjs`, …) say *which file*; this page says *why it works* and *which level to pick*.
|
|
4
|
+
|
|
5
|
+
The examples use the SvelteKit frontend (`@nebulr-group/bridge-svelte`) and the NestJS backend (`@nebulr-group/bridge-nestjs`), the two plugins with this surface today.
|
|
6
|
+
|
|
7
|
+
## The whole integration
|
|
8
|
+
|
|
9
|
+
What a developer's repo holds once Bridge is in. Nothing else is required; every other page Bridge needs, it serves.
|
|
10
|
+
|
|
11
|
+
**Frontend (SvelteKit) — 15 lines in four files, plus one line of `.env`:**
|
|
12
|
+
|
|
13
|
+
```env
|
|
14
|
+
# .env
|
|
15
|
+
VITE_BRIDGE_APP_ID=your-app-id
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
// src/routes/+layout.ts
|
|
20
|
+
import { bridgeBootstrap } from '@nebulr-group/bridge-svelte';
|
|
21
|
+
export const ssr = false;
|
|
22
|
+
export const load = bridgeBootstrap({ rules: [{ match: new RegExp('^/auth($|/)'), public: true }] });
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
```svelte
|
|
26
|
+
<!-- src/routes/+layout.svelte -->
|
|
27
|
+
<script lang="ts">
|
|
28
|
+
import { BridgeBootstrap } from '@nebulr-group/bridge-svelte';
|
|
29
|
+
import '@nebulr-group/bridge-svelte/styles';
|
|
30
|
+
let { children } = $props();
|
|
31
|
+
</script>
|
|
32
|
+
<BridgeBootstrap>
|
|
33
|
+
{@render children()}
|
|
34
|
+
</BridgeBootstrap>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```svelte
|
|
38
|
+
<!-- src/routes/auth/[...bridge]/+page.svelte — every sign-in page -->
|
|
39
|
+
<script lang="ts">
|
|
40
|
+
import { BridgeAuthRoutes } from '@nebulr-group/bridge-svelte';
|
|
41
|
+
</script>
|
|
42
|
+
<BridgeAuthRoutes />
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
With plans, one more four-line file serves the subscription page, the paywall and both checkout return pages:
|
|
46
|
+
|
|
47
|
+
```svelte
|
|
48
|
+
<!-- src/routes/subscription/[...bridge]/+page.svelte -->
|
|
49
|
+
<script lang="ts">
|
|
50
|
+
import { BridgeBillingRoutes } from '@nebulr-group/bridge-svelte';
|
|
51
|
+
</script>
|
|
52
|
+
<BridgeBillingRoutes />
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**Backend (NestJS) — 4 lines, plus one line of environment.** The lines marked `// +` are Bridge's; the rest is what `nest new` already gave you:
|
|
56
|
+
|
|
57
|
+
```env
|
|
58
|
+
# .env
|
|
59
|
+
BRIDGE_APP_ID=your-app-id
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
// src/app.module.ts
|
|
64
|
+
import { Module } from '@nestjs/common';
|
|
65
|
+
import { BridgeModule } from '@nebulr-group/bridge-nestjs'; // +
|
|
66
|
+
import { ExportsController } from './exports.controller';
|
|
67
|
+
|
|
68
|
+
@Module({
|
|
69
|
+
imports: [BridgeModule.forRoot({ guard: { global: true } })], // + every route needs a signed-in user
|
|
70
|
+
controllers: [ExportsController],
|
|
71
|
+
})
|
|
72
|
+
export class AppModule {}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
// src/exports.controller.ts
|
|
77
|
+
import { Controller, Post } from '@nestjs/common';
|
|
78
|
+
import { RequireQuota } from '@nebulr-group/bridge-nestjs'; // +
|
|
79
|
+
|
|
80
|
+
@Controller('exports')
|
|
81
|
+
export class ExportsController {
|
|
82
|
+
@Post()
|
|
83
|
+
@RequireQuota('exports') // + the plan limit
|
|
84
|
+
create() {
|
|
85
|
+
return { exported: true };
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
`BRIDGE_APP_ID` must be in the process environment. NestJS does not read `.env` by itself: start with `node --env-file=.env dist/main.js`, or set it in your container or process manager.
|
|
91
|
+
|
|
92
|
+
**Settings are read for you.** Each field resolves as *explicit option > environment > default*; an empty value counts as unset.
|
|
93
|
+
|
|
94
|
+
| Frontend | Backend | When to set it |
|
|
95
|
+
|---|---|---|
|
|
96
|
+
| `VITE_BRIDGE_APP_ID` | `BRIDGE_APP_ID` | Always. Missing, Bridge refuses to start and names the variable |
|
|
97
|
+
| `VITE_BRIDGE_API_BASE_URL` | `BRIDGE_API_BASE_URL` | Only for a non-production app (stage, local, self-hosted). Unset means production |
|
|
98
|
+
| `VITE_BRIDGE_HOSTED_URL` | — | Only for a local or self-hosted Bridge. On Bridge's own domains it follows the API address (`api-stage` → `auth-stage`) |
|
|
99
|
+
| `VITE_BRIDGE_DEBUG` | `BRIDGE_DEBUG` | `true` for console logging |
|
|
100
|
+
|
|
101
|
+
## 1. The server decides; the client decorates
|
|
102
|
+
|
|
103
|
+
Anyone can call your API with curl, so a limit or a paid feature is enforced on the backend handler, never in the browser. Everything the frontend shows about limits — the upgrade dialog, a disabled button, a hidden panel — explains or anticipates a decision the server already makes. Remove every frontend check and the product is still correct; remove the backend decorator and it is not.
|
|
104
|
+
|
|
105
|
+
## 2. A POST increments the limit
|
|
106
|
+
|
|
107
|
+
The backend decorator **is** the increment. There is nothing else to wire: no "report usage" call after the insert, no counter in your database, no endpoint for the frontend.
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
@Post()
|
|
111
|
+
@RequireQuota('exports')
|
|
112
|
+
create() { /* your code */ }
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
- **Before the handler:** at the plan's limit the request is refused with `402` and a body the frontend understands (`{ code: 'QUOTA_EXCEEDED', metric, used, limit, fix }`). Your handler never runs.
|
|
116
|
+
- **After the handler:** only when it answered **2xx**, Bridge records the use — exactly one write. A handler that throws or answers 4xx/5xx records nothing.
|
|
117
|
+
- **Retries:** a request that sends an `Idempotency-Key` header is counted once per key, however often the client retries.
|
|
118
|
+
- **Fail-closed:** if Bridge cannot answer, the request is refused with `503`, never let through unchecked.
|
|
119
|
+
- A `metered` quota never refuses: past its allowance it bills per unit.
|
|
120
|
+
|
|
121
|
+
## 3. Counter or gauge
|
|
122
|
+
|
|
123
|
+
**If deleting it frees room, it's a gauge and your app counts it; if it happened, it's a counter and Bridge counts it.**
|
|
124
|
+
|
|
125
|
+
| | Counter | Gauge |
|
|
126
|
+
|---|---|---|
|
|
127
|
+
| Examples | exports, API calls, AI completions, emails sent | tickets, projects, stored files, seats |
|
|
128
|
+
| Who counts | Bridge, one event per successful request | Your app — you pass your own count |
|
|
129
|
+
| Resets | every billing period ("40 of 100 this month") | never ("8 of 10 projects") |
|
|
130
|
+
| Configure | `bridge plan quota set <plan> --metric exports --limit 100 --policy hard` (counter is the default) | `bridge plan quota set <plan> --metric tickets --limit 10 --policy hard --kind gauge` |
|
|
131
|
+
| Backend | `@RequireQuota('exports')` | `@RequireQuota('tickets', { current })` on create, `@SyncQuota('tickets', { current })` on delete |
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
@Post()
|
|
135
|
+
@RequireQuota('tickets', { current: (t, self: TicketsController) => self.tickets.countFor(t.id) })
|
|
136
|
+
create() { /* … */ }
|
|
137
|
+
|
|
138
|
+
@Delete(':id')
|
|
139
|
+
@SyncQuota('tickets', { current: (t, self: TicketsController) => self.tickets.countFor(t.id) })
|
|
140
|
+
remove() { /* … */ }
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
`current` returns your own count, and that count is what the limit is compared against, so Bridge's copy heals itself if it ever missed an update. There is no decrement and no reservation: every create and delete sends the whole count.
|
|
144
|
+
|
|
145
|
+
**Seats** (`users`) are a gauge Bridge keeps itself from workspace membership. `@RequireQuota('users')` on your invite handler checks the seat limit and writes nothing.
|
|
146
|
+
|
|
147
|
+
`bridge plan quota list` shows every metric the app's plans limit, with its kind.
|
|
148
|
+
|
|
149
|
+
**Every hard quota is also an entitlement** with the same name, true while there is room. So never pair `@RequireEntitlement('exports')` with `@RequireQuota('exports')`: at the cap the entitlement answers `403` before the quota can answer the `402` the frontend knows how to upsell. Use `@RequireEntitlement` for a plan *feature* (`analytics`, `sso`), `@RequireQuota` for a *limit*.
|
|
150
|
+
|
|
151
|
+
**A plan feature is a hard quota nothing counts.** There is no separate entitlement setting: `bridge plan quota set pro --metric analytics --limit 1 --policy hard` makes `analytics` true on `pro`, and a plan without that quota answers false. Gate it with `@RequireEntitlement('analytics')` on the backend and `<Entitled to="analytics">` in the UI. `app_active` is always there: true while the workspace's subscription is active, trialing, past due or cancelling at period end.
|
|
152
|
+
|
|
153
|
+
## 4. Three ways to handle a limit in the UI
|
|
154
|
+
|
|
155
|
+
Pick the lowest level that does the job. Each is optional; level 0 is on without code.
|
|
156
|
+
|
|
157
|
+
| Level | What the page writes | What the user sees |
|
|
158
|
+
|---|---|---|
|
|
159
|
+
| **0 — nothing** | a plain button calling your API | Your backend refuses at the cap (`402`), and `<BridgeBootstrap>` opens an **upgrade dialog** naming the metric, linking to the subscription page. A workspace member who cannot manage billing is told to ask the owner instead |
|
|
160
|
+
| **1 — one component** | `<QuotaGate metric="tickets">…</QuotaGate>` around the button; `<Entitled to="analytics">…</Entitled>` around a paid feature | The button is disabled at a known hard cap with an upgrade line beside it; the paid feature shows only on a plan that grants it |
|
|
161
|
+
| **2 — your own UI** | `useQuota('tickets')` and `$entitlements.can('analytics')` | Whatever you build from the live numbers |
|
|
162
|
+
|
|
163
|
+
```svelte
|
|
164
|
+
<script lang="ts">
|
|
165
|
+
import { QuotaGate, Entitled, useQuota } from '@nebulr-group/bridge-svelte';
|
|
166
|
+
const tickets = useQuota('tickets');
|
|
167
|
+
</script>
|
|
168
|
+
|
|
169
|
+
<!-- level 1 -->
|
|
170
|
+
<QuotaGate metric="tickets">
|
|
171
|
+
<button onclick={createTicket}>New ticket</button>
|
|
172
|
+
</QuotaGate>
|
|
173
|
+
|
|
174
|
+
<Entitled to="analytics">
|
|
175
|
+
<a href="/analytics">Analytics</a>
|
|
176
|
+
{#snippet fallback()}<a href="/subscription">Upgrade for analytics</a>{/snippet}
|
|
177
|
+
</Entitled>
|
|
178
|
+
|
|
179
|
+
<!-- level 2 -->
|
|
180
|
+
{#if tickets.loading}
|
|
181
|
+
Loading…
|
|
182
|
+
{:else if tickets.unlimited}
|
|
183
|
+
Unlimited tickets
|
|
184
|
+
{:else}
|
|
185
|
+
{tickets.used} of {tickets.limit} tickets
|
|
186
|
+
{/if}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
- "Not loaded yet" is never "zero" and never "not allowed": `useQuota` numbers stay `null` while `loading`, `<QuotaGate>` stays enabled while loading, and `<Entitled>` renders nothing (or its `loading` snippet) until `$entitlements.ready`.
|
|
190
|
+
- The dialog catches a `402 QUOTA_EXCEEDED` from the page's own origin, from Bridge, and from any call made with `bridgeFetch()`; a backend on another origin is listed in `billing.apiOrigins`. `billing: { upgradeDialog: false }` turns it off, `billing: { upgradeDialog: MyDialog }` replaces it.
|
|
191
|
+
- Do not write a quota `if`, a "limit reached" toast or a `/quota` endpoint of your own: level 0 already covers the refusal, and the frontend reads quota directly from Bridge.
|
|
192
|
+
|
|
193
|
+
## 5. Usage reported from the browser trusts the client
|
|
194
|
+
|
|
195
|
+
An app with no backend that sees the action — local-first, mobile, data on the device — can report usage from the frontend:
|
|
196
|
+
|
|
197
|
+
```ts
|
|
198
|
+
import { bridge } from '@nebulr-group/bridge-svelte';
|
|
199
|
+
|
|
200
|
+
bridge.usage.report('exports'); // a counter: it happened
|
|
201
|
+
await bridge.usage.set('projects', projects.length); // a gauge: how many exist now
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
This is **self-reported, trusted-client usage**. Anything in a browser can send any number, so **a frontend alone cannot enforce a limit**: Bridge shows and bills what the client reports, and the client can lie. When the app has a backend, report and enforce there (section 2). Use the browser path only when there is no server to do it.
|
|
205
|
+
|
|
206
|
+
## 6. Four levels of customising Bridge's pages
|
|
207
|
+
|
|
208
|
+
The same ladder holds for the sign-in pages (`<BridgeAuthRoutes>`) and the subscription pages (`<BridgeBillingRoutes>`). Climb only as far as you need.
|
|
209
|
+
|
|
210
|
+
| Rung | What you do | What you own |
|
|
211
|
+
|---|---|---|
|
|
212
|
+
| **0 — nothing** | Bridge's pages render inside your own `+layout.svelte` | Your navigation, header and shell already surround them |
|
|
213
|
+
| **1 — tokens** | Set `--bridge-*` CSS variables in your CSS | Colours, radius, spacing |
|
|
214
|
+
| **2 — frame and heading** | Pass the `frame(page, children)` and `heading(page)` snippets | Everything around the form on every page, and each page's heading |
|
|
215
|
+
| **3 — take over one page** | Create that page's own route file, e.g. `src/routes/auth/login/+page.svelte` | That one page; SvelteKit prefers it over `[...bridge]`, every other page keeps working |
|
|
216
|
+
| **4 — headless** | Build your own UI on `getBridgeAuth()` | Everything |
|
|
217
|
+
|
|
218
|
+
```svelte
|
|
219
|
+
<!-- rung 2: src/routes/auth/[...bridge]/+page.svelte -->
|
|
220
|
+
<script lang="ts">
|
|
221
|
+
import { BridgeAuthRoutes } from '@nebulr-group/bridge-svelte';
|
|
222
|
+
</script>
|
|
223
|
+
|
|
224
|
+
<BridgeAuthRoutes>
|
|
225
|
+
{#snippet frame(page, children)}
|
|
226
|
+
<main class="auth-card">{@render children()}</main>
|
|
227
|
+
{/snippet}
|
|
228
|
+
{#snippet heading(page)}
|
|
229
|
+
<h1>{page === 'signup' ? 'Create your account' : 'Welcome back'}</h1>
|
|
230
|
+
{/snippet}
|
|
231
|
+
</BridgeAuthRoutes>
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
`heading` replaces only each page's main step (the login credentials step, the signup form, the set-password form); sub-steps such as "Reset your password" keep their own, so two headings never stack. There are no per-page snippets: to change more than frame and heading, take over the page (rung 3). A sign-in page you own navigates itself after sign-in: `<LoginForm onLogin={() => goto(readReturnTo($page.url) ?? '/')} />`.
|
|
235
|
+
|
|
236
|
+
**The token contract (rung 1).** These `--bridge-*` variables are the supported way to restyle the components; each has a built-in default. Set them on `:root` or on any wrapper.
|
|
237
|
+
|
|
238
|
+
| Token | Default | Styles |
|
|
239
|
+
|---|---|---|
|
|
240
|
+
| `--bridge-primary` | `#4f46e5` | Primary buttons, selected plan interval, active workspace border |
|
|
241
|
+
| `--bridge-primary-hover` | `#4338ca` | Primary button hover |
|
|
242
|
+
| `--bridge-primary-fg` | `#ffffff` | Text on primary buttons |
|
|
243
|
+
| `--bridge-primary-foreground` | `#ffffff` | Workspace avatar text; plan picker fallback when `--bridge-primary-fg` is unset |
|
|
244
|
+
| `--bridge-primary-light` | `#eff6ff` | Active workspace background |
|
|
245
|
+
| `--bridge-border` | `#d1d5db` | Input and secondary button borders |
|
|
246
|
+
| `--bridge-border-radius` | `6px` | Corners of inputs, buttons, alerts, cards |
|
|
247
|
+
| `--bridge-input-focus` | `#4f46e5` | Input focus ring |
|
|
248
|
+
| `--bridge-foreground` | `#374151` | Password-toggle hover, workspace names |
|
|
249
|
+
| `--bridge-muted` | `#6b7280` | Secondary text, hints, table headings |
|
|
250
|
+
| `--bridge-bg` | `#ffffff` | Plan-change confirmation panel |
|
|
251
|
+
| `--bridge-bg-muted` | `#f5f5f5` | MFA backup code |
|
|
252
|
+
| `--bridge-muted-bg` | `#f3f4f6` | Workspace list hover, plan interval tabs (which fall back to `--bridge-bg-muted`) |
|
|
253
|
+
| `--bridge-alert-error-bg` | `#fef2f2` | Error alert background |
|
|
254
|
+
| `--bridge-alert-error-fg` | `#991b1b` | Error alert text |
|
|
255
|
+
| `--bridge-alert-error-border` | `#fca5a5` | Error alert border |
|
|
256
|
+
| `--bridge-alert-success-bg` | `#f0fdf4` | Success alert background |
|
|
257
|
+
| `--bridge-alert-success-fg` | `#166534` | Success alert text |
|
|
258
|
+
| `--bridge-alert-success-border` | `#86efac` | Success alert border |
|
|
259
|
+
| `--bridge-auth-page-padding` | `3rem 1rem` | Padding of the default sign-in page container |
|
|
260
|
+
| `--bridge-billing-page-width` | `60rem` | Width of the subscription pages and `<BridgePaywallPage>` |
|
|
261
|
+
| `--bridge-billing-page-padding` | `3rem 1rem` | Padding of the subscription pages and `<BridgePaywallPage>` |
|
|
262
|
+
| `--bridge-paywall-bg` | `rgba(15, 23, 42, 0.72)` | Backdrop of the `<BridgePaywall>` overlay |
|
|
263
|
+
| `--bridge-paywall-panel-bg` | `#ffffff` | Panel of the `<BridgePaywall>` overlay |
|
|
264
|
+
|
|
265
|
+
All default rules use `:where()`, so any selector of yours wins without `!important`. Leaving out `import '@nebulr-group/bridge-svelte/styles'` makes the components headless: plain HTML for you to style.
|
|
266
|
+
|
|
267
|
+
## 7. Pages Bridge serves, and the one it only offers
|
|
268
|
+
|
|
269
|
+
- **Sign-in:** `src/routes/auth/[...bridge]/+page.svelte` serves login, signup, the OAuth callback, set password (where signup verification and password-reset emails land), forgot password, magic link, passkey setup and workspace selection. Which methods appear comes from the app's settings at runtime, so turning magic links on needs no code. Hosted and in-app sign-in use the same file; `loginRoute: '/auth/login'` in `bridgeBootstrap()` is the whole switch to in-app.
|
|
270
|
+
- **Subscription:** `src/routes/subscription/[...bridge]/+page.svelte` serves `/subscription`, the paywall `/subscription/plan`, and the checkout return pages `/subscription/success` and `/subscription/error`. Bridge's redirects and upgrade links point there by default.
|
|
271
|
+
- **The paywall** redirects a signed-in workspace with no plan to `/subscription/plan` before any page renders — only when the app has plans and its `paymentsAutoRedirect` setting is on (the default). `bridge app update --payments-auto-redirect false` turns it off.
|
|
272
|
+
- **A `/welcome` onboarding page is offered, never created unasked.** It is a product decision: ask the developer. Only if they say yes, add a one-line page rendering `<BridgePaywallPage />` and `billing: { paywallRoute: '/welcome' }` in `bridgeBootstrap()`.
|
|
273
|
+
- Any other address under a catch-all gets the app's own 404.
|
|
274
|
+
|
|
275
|
+
## Where the details live
|
|
276
|
+
|
|
277
|
+
| Topic | Command |
|
|
278
|
+
|---|---|
|
|
279
|
+
| Sign-in, hosted or in-app | `bridge guide svelte` · `bridge guide svelte sdk-auth` |
|
|
280
|
+
| Plans, the subscription pages, the UI levels | `bridge guide svelte billing` |
|
|
281
|
+
| Backend limits and entitlements | `bridge guide nestjs billing` |
|
|
282
|
+
| Backend sign-in and route protection | `bridge guide nestjs` |
|
|
283
|
+
| Feature flags | `bridge guide flags` |
|
|
284
|
+
| Proving sign-in works | `bridge test-user create`, then `bridge test-user verify` |
|