@littlebearapps/platform-admin-sdk 1.0.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.
Files changed (94) hide show
  1. package/README.md +112 -0
  2. package/dist/index.d.ts +16 -0
  3. package/dist/index.js +89 -0
  4. package/dist/prompts.d.ts +27 -0
  5. package/dist/prompts.js +80 -0
  6. package/dist/scaffold.d.ts +5 -0
  7. package/dist/scaffold.js +65 -0
  8. package/dist/templates.d.ts +16 -0
  9. package/dist/templates.js +131 -0
  10. package/package.json +46 -0
  11. package/templates/full/migrations/006_pattern_discovery.sql +199 -0
  12. package/templates/full/migrations/007_notifications_search.sql +127 -0
  13. package/templates/full/workers/lib/pattern-discovery/ai-prompt.ts +644 -0
  14. package/templates/full/workers/lib/pattern-discovery/clustering.ts +278 -0
  15. package/templates/full/workers/lib/pattern-discovery/shadow-evaluation.ts +603 -0
  16. package/templates/full/workers/lib/pattern-discovery/storage.ts +806 -0
  17. package/templates/full/workers/lib/pattern-discovery/types.ts +159 -0
  18. package/templates/full/workers/lib/pattern-discovery/validation.ts +278 -0
  19. package/templates/full/workers/pattern-discovery.ts +661 -0
  20. package/templates/full/workers/platform-alert-router.ts +1809 -0
  21. package/templates/full/workers/platform-notifications.ts +424 -0
  22. package/templates/full/workers/platform-search.ts +480 -0
  23. package/templates/full/workers/platform-settings.ts +436 -0
  24. package/templates/full/wrangler.alert-router.jsonc.hbs +34 -0
  25. package/templates/full/wrangler.notifications.jsonc.hbs +23 -0
  26. package/templates/full/wrangler.pattern-discovery.jsonc.hbs +33 -0
  27. package/templates/full/wrangler.search.jsonc.hbs +16 -0
  28. package/templates/full/wrangler.settings.jsonc.hbs +23 -0
  29. package/templates/shared/README.md.hbs +69 -0
  30. package/templates/shared/config/budgets.yaml.hbs +72 -0
  31. package/templates/shared/config/services.yaml.hbs +45 -0
  32. package/templates/shared/migrations/001_core_tables.sql +117 -0
  33. package/templates/shared/migrations/002_usage_warehouse.sql +830 -0
  34. package/templates/shared/migrations/003_feature_tracking.sql +250 -0
  35. package/templates/shared/migrations/004_settings_alerts.sql +452 -0
  36. package/templates/shared/migrations/seed.sql.hbs +4 -0
  37. package/templates/shared/package.json.hbs +21 -0
  38. package/templates/shared/scripts/sync-config.ts +242 -0
  39. package/templates/shared/tsconfig.json +12 -0
  40. package/templates/shared/workers/lib/analytics-engine.ts +357 -0
  41. package/templates/shared/workers/lib/billing.ts +293 -0
  42. package/templates/shared/workers/lib/circuit-breaker-middleware.ts +25 -0
  43. package/templates/shared/workers/lib/control.ts +292 -0
  44. package/templates/shared/workers/lib/economics.ts +368 -0
  45. package/templates/shared/workers/lib/metrics.ts +103 -0
  46. package/templates/shared/workers/lib/platform-settings.ts +407 -0
  47. package/templates/shared/workers/lib/shared/allowances.ts +333 -0
  48. package/templates/shared/workers/lib/shared/cloudflare.ts +1362 -0
  49. package/templates/shared/workers/lib/shared/types.ts +58 -0
  50. package/templates/shared/workers/lib/telemetry-sampling.ts +360 -0
  51. package/templates/shared/workers/lib/usage/collectors/example.ts +96 -0
  52. package/templates/shared/workers/lib/usage/collectors/index.ts +128 -0
  53. package/templates/shared/workers/lib/usage/handlers/audit.ts +306 -0
  54. package/templates/shared/workers/lib/usage/handlers/backfill.ts +845 -0
  55. package/templates/shared/workers/lib/usage/handlers/behavioral.ts +429 -0
  56. package/templates/shared/workers/lib/usage/handlers/data-queries.ts +507 -0
  57. package/templates/shared/workers/lib/usage/handlers/dlq-admin.ts +364 -0
  58. package/templates/shared/workers/lib/usage/handlers/health-trends.ts +222 -0
  59. package/templates/shared/workers/lib/usage/handlers/index.ts +35 -0
  60. package/templates/shared/workers/lib/usage/handlers/usage-admin.ts +421 -0
  61. package/templates/shared/workers/lib/usage/handlers/usage-features.ts +1262 -0
  62. package/templates/shared/workers/lib/usage/handlers/usage-metrics.ts +2420 -0
  63. package/templates/shared/workers/lib/usage/handlers/usage-settings.ts +610 -0
  64. package/templates/shared/workers/lib/usage/queue/budget-enforcement.ts +1032 -0
  65. package/templates/shared/workers/lib/usage/queue/cost-budget-enforcement.ts +128 -0
  66. package/templates/shared/workers/lib/usage/queue/cost-calculator.ts +77 -0
  67. package/templates/shared/workers/lib/usage/queue/dlq-handler.ts +161 -0
  68. package/templates/shared/workers/lib/usage/queue/index.ts +19 -0
  69. package/templates/shared/workers/lib/usage/queue/telemetry-processor.ts +790 -0
  70. package/templates/shared/workers/lib/usage/scheduled/anomaly-detection.ts +732 -0
  71. package/templates/shared/workers/lib/usage/scheduled/data-collection.ts +956 -0
  72. package/templates/shared/workers/lib/usage/scheduled/error-digest.ts +343 -0
  73. package/templates/shared/workers/lib/usage/scheduled/index.ts +18 -0
  74. package/templates/shared/workers/lib/usage/scheduled/rollups.ts +1561 -0
  75. package/templates/shared/workers/lib/usage/shared/constants.ts +362 -0
  76. package/templates/shared/workers/lib/usage/shared/index.ts +14 -0
  77. package/templates/shared/workers/lib/usage/shared/types.ts +1066 -0
  78. package/templates/shared/workers/lib/usage/shared/utils.ts +795 -0
  79. package/templates/shared/workers/platform-usage.ts +1915 -0
  80. package/templates/shared/wrangler.usage.jsonc.hbs +58 -0
  81. package/templates/standard/migrations/005_error_collection.sql +162 -0
  82. package/templates/standard/workers/error-collector.ts +2670 -0
  83. package/templates/standard/workers/lib/error-collector/capture.ts +213 -0
  84. package/templates/standard/workers/lib/error-collector/digest.ts +448 -0
  85. package/templates/standard/workers/lib/error-collector/email-health-alerts.ts +262 -0
  86. package/templates/standard/workers/lib/error-collector/fingerprint.ts +258 -0
  87. package/templates/standard/workers/lib/error-collector/gap-alerts.ts +293 -0
  88. package/templates/standard/workers/lib/error-collector/github.ts +329 -0
  89. package/templates/standard/workers/lib/error-collector/types.ts +262 -0
  90. package/templates/standard/workers/lib/sentinel/gap-detection.ts +734 -0
  91. package/templates/standard/workers/lib/shared/slack-alerts.ts +585 -0
  92. package/templates/standard/workers/platform-sentinel.ts +1744 -0
  93. package/templates/standard/wrangler.error-collector.jsonc.hbs +44 -0
  94. package/templates/standard/wrangler.sentinel.jsonc.hbs +45 -0
package/README.md ADDED
@@ -0,0 +1,112 @@
1
+ # Platform Admin SDK
2
+
3
+ **`@littlebearapps/platform-admin-sdk`** — Scaffold backend infrastructure for Cloudflare Workers cost protection.
4
+
5
+ Generates workers, D1 migrations, and config files. Run once, then you own the code.
6
+
7
+ ## Usage
8
+
9
+ ```bash
10
+ npx @littlebearapps/platform-admin-sdk my-platform
11
+ ```
12
+
13
+ The CLI prompts for:
14
+ - **Project name** and slug
15
+ - **GitHub organisation** (for error collection GitHub issues)
16
+ - **Tier** — how much infrastructure to generate
17
+ - **Gatus URL** (optional) — for heartbeat monitoring
18
+ - **Default assignee** — GitHub username for error issues
19
+
20
+ ### CLI Flags (non-interactive)
21
+
22
+ ```bash
23
+ npx @littlebearapps/platform-admin-sdk my-platform --tier full --github-org myorg --skip-prompts
24
+ ```
25
+
26
+ | Flag | Description |
27
+ |------|------------|
28
+ | `--tier <tier>` | Infrastructure tier (`minimal`, `standard`, `full`) |
29
+ | `--github-org <org>` | GitHub organisation for error issues |
30
+ | `--gatus-url <url>` | Gatus status page URL |
31
+ | `--default-assignee <user>` | Default GitHub issue assignee |
32
+ | `--skip-prompts` | Fail if required flags missing (for CI/automation) |
33
+
34
+ ## Tiers
35
+
36
+ | Tier | Workers | What You Get | Est. Cost |
37
+ |------|---------|-------------|-----------|
38
+ | **Minimal** | 1 | Budget enforcement, circuit breakers, usage telemetry | ~$0/mo |
39
+ | **Standard** | 3 | + Error collector (auto GitHub issues), gap detection sentinel | ~$0/mo |
40
+ | **Full** | 8 | + AI pattern discovery, alert router, notifications, search, settings | ~$5/mo |
41
+
42
+ ## What Gets Generated
43
+
44
+ ### All tiers
45
+
46
+ ```
47
+ my-platform/
48
+ +-- platform/config/
49
+ | +-- services.yaml # Project registry, feature definitions
50
+ | +-- budgets.yaml # Daily limits, circuit breaker thresholds
51
+ +-- storage/d1/migrations/ # D1 schema (4 core migrations + seed)
52
+ +-- workers/
53
+ | +-- platform-usage.ts # Data warehouse worker (cron + queue consumer)
54
+ | +-- lib/ # Shared libraries (billing, analytics, budgets)
55
+ +-- scripts/
56
+ | +-- sync-config.ts # Sync YAML config to D1/KV
57
+ +-- wrangler.*.jsonc # Worker configs with binding placeholders
58
+ +-- package.json
59
+ +-- tsconfig.json
60
+ +-- README.md
61
+ ```
62
+
63
+ ### Standard tier adds
64
+
65
+ - `workers/error-collector.ts` — Tail worker that creates GitHub issues from errors
66
+ - `workers/platform-sentinel.ts` — Gap detection, cost monitoring, alerts
67
+ - `workers/lib/error-collector/` — Fingerprinting, deduplication, digest
68
+ - `workers/lib/sentinel/` — Project gap detection
69
+ - `storage/d1/migrations/005_error_collection.sql`
70
+
71
+ ### Full tier adds
72
+
73
+ - `workers/pattern-discovery.ts` — AI-assisted transient error pattern discovery
74
+ - `workers/platform-alert-router.ts` — Unified alert normalisation and routing
75
+ - `workers/platform-notifications.ts` — In-app notification API
76
+ - `workers/platform-search.ts` — Full-text search (FTS5)
77
+ - `workers/platform-settings.ts` — Settings management API
78
+ - `workers/lib/pattern-discovery/` — Clustering, AI prompts, validation, shadow eval
79
+ - `storage/d1/migrations/006_pattern_discovery.sql`
80
+ - `storage/d1/migrations/007_notifications_search.sql`
81
+
82
+ ## Post-Scaffold Steps
83
+
84
+ ```bash
85
+ cd my-platform
86
+ npm install
87
+
88
+ # Create Cloudflare resources
89
+ npx wrangler d1 create my-platform-metrics
90
+ npx wrangler kv namespace create PLATFORM_CACHE
91
+ npx wrangler queues create my-platform-telemetry
92
+ npx wrangler queues create my-platform-telemetry-dlq
93
+
94
+ # Update resource IDs in wrangler.*.jsonc, then:
95
+ npm run sync:config
96
+ npx wrangler d1 migrations apply my-platform-metrics --remote
97
+ npx wrangler deploy -c wrangler.my-platform-usage.jsonc
98
+ ```
99
+
100
+ ## Consumer SDK
101
+
102
+ The generated workers use `@littlebearapps/platform-consumer-sdk` — the Consumer SDK. Install it in your application workers:
103
+
104
+ ```bash
105
+ npm install @littlebearapps/platform-consumer-sdk
106
+ ```
107
+
108
+ See the [Consumer SDK README](../consumer-sdk/README.md) for integration details.
109
+
110
+ ## License
111
+
112
+ MIT
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @littlebearapps/platform-admin-sdk
4
+ *
5
+ * Scaffolds a Cloudflare Workers platform with SDK integration,
6
+ * circuit breakers, and cost protection.
7
+ *
8
+ * Usage:
9
+ * npx @littlebearapps/platform-admin-sdk [project-name] [options]
10
+ *
11
+ * Examples:
12
+ * npx @littlebearapps/platform-admin-sdk my-project
13
+ * npx @littlebearapps/platform-admin-sdk my-project --tier full --github-org myorg
14
+ * npx @littlebearapps/platform-admin-sdk my-project --tier minimal --skip-prompts
15
+ */
16
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @littlebearapps/platform-admin-sdk
4
+ *
5
+ * Scaffolds a Cloudflare Workers platform with SDK integration,
6
+ * circuit breakers, and cost protection.
7
+ *
8
+ * Usage:
9
+ * npx @littlebearapps/platform-admin-sdk [project-name] [options]
10
+ *
11
+ * Examples:
12
+ * npx @littlebearapps/platform-admin-sdk my-project
13
+ * npx @littlebearapps/platform-admin-sdk my-project --tier full --github-org myorg
14
+ * npx @littlebearapps/platform-admin-sdk my-project --tier minimal --skip-prompts
15
+ */
16
+ import { resolve } from 'node:path';
17
+ import { Command } from 'commander';
18
+ import pc from 'picocolors';
19
+ import { collectOptions, isValidTier } from './prompts.js';
20
+ import { scaffold } from './scaffold.js';
21
+ const BANNER = `
22
+ ${pc.bold(pc.cyan('Platform Admin SDK'))} — Cloudflare Cost Protection
23
+ ${pc.dim('Scaffold backend infrastructure: circuit breakers, budget enforcement, error collection')}
24
+ `;
25
+ const program = new Command()
26
+ .name('platform-admin-sdk')
27
+ .description('Scaffold a Cloudflare Workers platform with SDK integration')
28
+ .version('1.0.0')
29
+ .argument('[project-name]', 'Name of the project to create')
30
+ .option('--tier <tier>', 'Infrastructure tier (minimal, standard, full)')
31
+ .option('--github-org <org>', 'GitHub organisation for error issue creation')
32
+ .option('--gatus-url <url>', 'Gatus status page URL for heartbeat monitoring')
33
+ .option('--default-assignee <user>', 'Default GitHub assignee for error issues')
34
+ .option('--skip-prompts', 'Non-interactive mode — fail if required flags are missing');
35
+ async function main() {
36
+ console.log(BANNER);
37
+ program.parse();
38
+ const opts = program.opts();
39
+ const [projectNameArg] = program.args;
40
+ // Validate tier if provided
41
+ if (opts.tier && !isValidTier(opts.tier)) {
42
+ console.error(pc.red(` Error: Invalid tier "${opts.tier}". Must be one of: minimal, standard, full`));
43
+ process.exit(1);
44
+ }
45
+ const options = await collectOptions({
46
+ projectName: projectNameArg,
47
+ tier: opts.tier,
48
+ githubOrg: opts.githubOrg,
49
+ gatusUrl: opts.gatusUrl,
50
+ defaultAssignee: opts.defaultAssignee,
51
+ skipPrompts: opts.skipPrompts,
52
+ });
53
+ const outputDir = resolve(process.cwd(), options.projectName);
54
+ console.log();
55
+ console.log(` ${pc.bold('Project')}: ${options.projectName}`);
56
+ console.log(` ${pc.bold('Tier')}: ${options.tier}`);
57
+ console.log(` ${pc.bold('Output')}: ${outputDir}`);
58
+ console.log();
59
+ await scaffold(options, outputDir);
60
+ console.log();
61
+ console.log(pc.green(pc.bold(' Done!')));
62
+ console.log();
63
+ console.log(` ${pc.bold('Next steps:')}`);
64
+ console.log();
65
+ console.log(` ${pc.cyan('cd')} ${options.projectName}`);
66
+ console.log(` ${pc.cyan('npm install')}`);
67
+ console.log();
68
+ console.log(` ${pc.dim('# Create Cloudflare resources:')}`);
69
+ console.log(` ${pc.cyan('npx wrangler d1 create')} ${options.projectSlug}-metrics`);
70
+ console.log(` ${pc.cyan('npx wrangler kv namespace create')} PLATFORM_CACHE`);
71
+ if (options.tier !== 'minimal') {
72
+ console.log(` ${pc.cyan('npx wrangler kv namespace create')} PLATFORM_ALERTS`);
73
+ }
74
+ console.log(` ${pc.cyan('npx wrangler queues create')} ${options.projectSlug}-telemetry`);
75
+ console.log(` ${pc.cyan('npx wrangler queues create')} ${options.projectSlug}-telemetry-dlq`);
76
+ console.log();
77
+ console.log(` ${pc.dim('# Update resource IDs in wrangler.*.jsonc, then:')}`);
78
+ console.log(` ${pc.cyan('npm run sync:config')}`);
79
+ console.log(` ${pc.cyan('npx wrangler d1 migrations apply')} ${options.projectSlug}-metrics --remote`);
80
+ console.log(` ${pc.cyan('npx wrangler deploy')} -c wrangler.${options.projectSlug}-usage.jsonc`);
81
+ console.log();
82
+ console.log(` ${pc.dim('# In your consumer projects:')}`);
83
+ console.log(` ${pc.cyan('npm install @littlebearapps/platform-consumer-sdk')}`);
84
+ console.log();
85
+ }
86
+ main().catch((error) => {
87
+ console.error(pc.red('Error:'), error instanceof Error ? error.message : String(error));
88
+ process.exit(1);
89
+ });
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Interactive CLI prompts for project scaffolding configuration.
3
+ *
4
+ * When flags are provided via CLI, those values are used without prompting.
5
+ * Falls back to interactive prompts for missing values, or sensible defaults
6
+ * when running non-interactively.
7
+ */
8
+ export type Tier = 'minimal' | 'standard' | 'full';
9
+ export interface ScaffoldOptions {
10
+ projectName: string;
11
+ projectSlug: string;
12
+ githubOrg: string;
13
+ tier: Tier;
14
+ gatusUrl: string;
15
+ defaultAssignee: string;
16
+ }
17
+ /** Pre-filled values from CLI flags. */
18
+ export interface CLIFlags {
19
+ projectName?: string;
20
+ tier?: Tier;
21
+ githubOrg?: string;
22
+ gatusUrl?: string;
23
+ defaultAssignee?: string;
24
+ skipPrompts?: boolean;
25
+ }
26
+ export declare function isValidTier(value: string): value is Tier;
27
+ export declare function collectOptions(flags?: CLIFlags): Promise<ScaffoldOptions>;
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Interactive CLI prompts for project scaffolding configuration.
3
+ *
4
+ * When flags are provided via CLI, those values are used without prompting.
5
+ * Falls back to interactive prompts for missing values, or sensible defaults
6
+ * when running non-interactively.
7
+ */
8
+ import * as readline from 'node:readline';
9
+ const VALID_TIERS = ['minimal', 'standard', 'full'];
10
+ export function isValidTier(value) {
11
+ return VALID_TIERS.includes(value);
12
+ }
13
+ function slugify(name) {
14
+ return name
15
+ .toLowerCase()
16
+ .replace(/[^a-z0-9]+/g, '-')
17
+ .replace(/^-|-$/g, '');
18
+ }
19
+ async function prompt(question, defaultValue) {
20
+ // Non-interactive: use defaults
21
+ if (!process.stdin.isTTY) {
22
+ return defaultValue;
23
+ }
24
+ const rl = readline.createInterface({
25
+ input: process.stdin,
26
+ output: process.stdout,
27
+ });
28
+ return new Promise((resolve) => {
29
+ const display = defaultValue ? `${question} (${defaultValue}): ` : `${question}: `;
30
+ rl.question(` ${display}`, (answer) => {
31
+ rl.close();
32
+ resolve(answer.trim() || defaultValue);
33
+ });
34
+ });
35
+ }
36
+ async function promptSelect(question, options, defaultIndex = 0) {
37
+ if (!process.stdin.isTTY) {
38
+ return options[defaultIndex];
39
+ }
40
+ console.log(` ${question}`);
41
+ options.forEach((opt, i) => {
42
+ const marker = i === defaultIndex ? '>' : ' ';
43
+ console.log(` ${marker} ${i + 1}. ${opt}`);
44
+ });
45
+ const answer = await prompt('Choose', String(defaultIndex + 1));
46
+ const idx = parseInt(answer, 10) - 1;
47
+ return options[idx] ?? options[defaultIndex];
48
+ }
49
+ export async function collectOptions(flags = {}) {
50
+ if (flags.skipPrompts) {
51
+ if (!flags.projectName) {
52
+ throw new Error('--skip-prompts requires a project name argument');
53
+ }
54
+ if (!flags.tier) {
55
+ throw new Error('--skip-prompts requires --tier');
56
+ }
57
+ return {
58
+ projectName: flags.projectName,
59
+ projectSlug: slugify(flags.projectName),
60
+ githubOrg: flags.githubOrg ?? '',
61
+ tier: flags.tier,
62
+ gatusUrl: flags.gatusUrl ?? '',
63
+ defaultAssignee: flags.defaultAssignee ?? '',
64
+ };
65
+ }
66
+ const projectName = flags.projectName || await prompt('Project name', 'my-platform');
67
+ const projectSlug = await prompt('Project slug (for resource names)', slugify(projectName));
68
+ const tier = flags.tier || await promptSelect('Setup tier:', VALID_TIERS, 1);
69
+ const githubOrg = flags.githubOrg ?? await prompt('GitHub org (for error issue creation)', '');
70
+ const gatusUrl = flags.gatusUrl ?? await prompt('Gatus status page URL (optional)', '');
71
+ const defaultAssignee = flags.defaultAssignee ?? await prompt('Default GitHub assignee (optional)', '');
72
+ return {
73
+ projectName,
74
+ projectSlug,
75
+ githubOrg,
76
+ tier,
77
+ gatusUrl,
78
+ defaultAssignee,
79
+ };
80
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Scaffolding orchestrator — copies and renders templates into the output directory.
3
+ */
4
+ import type { ScaffoldOptions } from './prompts.js';
5
+ export declare function scaffold(options: ScaffoldOptions, outputDir: string): Promise<void>;
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Scaffolding orchestrator — copies and renders templates into the output directory.
3
+ */
4
+ import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs';
5
+ import { resolve, dirname, join } from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+ import Handlebars from 'handlebars';
8
+ import pc from 'picocolors';
9
+ import { getFilesForTier } from './templates.js';
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = dirname(__filename);
12
+ function getTemplatesDir() {
13
+ // In development: ../templates/
14
+ // In published package: ../templates/ (relative to dist/)
15
+ const devPath = resolve(__dirname, '..', 'templates');
16
+ if (existsSync(devPath))
17
+ return devPath;
18
+ return resolve(__dirname, '..', '..', 'templates');
19
+ }
20
+ function renderString(template, context) {
21
+ // Simple {{var}} replacement for file paths (not Handlebars — just string replace)
22
+ let result = template;
23
+ for (const [key, value] of Object.entries(context)) {
24
+ result = result.replace(new RegExp(`\\{\\{${key}\\}\\}`, 'g'), value);
25
+ }
26
+ return result;
27
+ }
28
+ export async function scaffold(options, outputDir) {
29
+ if (existsSync(outputDir)) {
30
+ throw new Error(`Directory already exists: ${outputDir}`);
31
+ }
32
+ const templatesDir = getTemplatesDir();
33
+ const files = getFilesForTier(options.tier);
34
+ const context = {
35
+ projectName: options.projectName,
36
+ projectSlug: options.projectSlug,
37
+ githubOrg: options.githubOrg,
38
+ tier: options.tier,
39
+ gatusUrl: options.gatusUrl,
40
+ defaultAssignee: options.defaultAssignee,
41
+ sdkVersion: '0.2.0',
42
+ };
43
+ mkdirSync(outputDir, { recursive: true });
44
+ for (const file of files) {
45
+ const srcPath = join(templatesDir, file.src);
46
+ const destPath = join(outputDir, renderString(file.dest, context));
47
+ // Ensure destination directory exists
48
+ mkdirSync(dirname(destPath), { recursive: true });
49
+ if (!existsSync(srcPath)) {
50
+ console.log(` ${pc.yellow('skip')} ${file.src} ${pc.dim('(template not found)')}`);
51
+ continue;
52
+ }
53
+ const raw = readFileSync(srcPath, 'utf-8');
54
+ if (file.template) {
55
+ const compiled = Handlebars.compile(raw, { noEscape: true });
56
+ const rendered = compiled(context);
57
+ writeFileSync(destPath, rendered);
58
+ }
59
+ else {
60
+ writeFileSync(destPath, raw);
61
+ }
62
+ const relDest = destPath.replace(outputDir + '/', '');
63
+ console.log(` ${pc.green('create')} ${relDest}`);
64
+ }
65
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Template manifest — maps tiers to files that should be scaffolded.
3
+ *
4
+ * Files ending in .hbs are rendered through Handlebars.
5
+ * All other files are copied verbatim.
6
+ */
7
+ import type { Tier } from './prompts.js';
8
+ export interface TemplateFile {
9
+ /** Path relative to the templates/ directory */
10
+ src: string;
11
+ /** Path relative to the output directory */
12
+ dest: string;
13
+ /** Whether this file uses Handlebars templating */
14
+ template: boolean;
15
+ }
16
+ export declare function getFilesForTier(tier: Tier): TemplateFile[];
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Template manifest — maps tiers to files that should be scaffolded.
3
+ *
4
+ * Files ending in .hbs are rendered through Handlebars.
5
+ * All other files are copied verbatim.
6
+ */
7
+ const SHARED_FILES = [
8
+ // Config
9
+ { src: 'shared/config/services.yaml.hbs', dest: 'platform/config/services.yaml', template: true },
10
+ { src: 'shared/config/budgets.yaml.hbs', dest: 'platform/config/budgets.yaml', template: true },
11
+ // Scripts
12
+ { src: 'shared/scripts/sync-config.ts', dest: 'scripts/sync-config.ts', template: false },
13
+ // Migrations (minimal tier)
14
+ { src: 'shared/migrations/001_core_tables.sql', dest: 'storage/d1/migrations/001_core_tables.sql', template: false },
15
+ { src: 'shared/migrations/002_usage_warehouse.sql', dest: 'storage/d1/migrations/002_usage_warehouse.sql', template: false },
16
+ { src: 'shared/migrations/003_feature_tracking.sql', dest: 'storage/d1/migrations/003_feature_tracking.sql', template: false },
17
+ { src: 'shared/migrations/004_settings_alerts.sql', dest: 'storage/d1/migrations/004_settings_alerts.sql', template: false },
18
+ { src: 'shared/migrations/seed.sql.hbs', dest: 'storage/d1/migrations/seed.sql', template: true },
19
+ // Wrangler config (minimal)
20
+ { src: 'shared/wrangler.usage.jsonc.hbs', dest: 'wrangler.{{projectSlug}}-usage.jsonc', template: true },
21
+ // Project files
22
+ { src: 'shared/package.json.hbs', dest: 'package.json', template: true },
23
+ { src: 'shared/tsconfig.json', dest: 'tsconfig.json', template: false },
24
+ { src: 'shared/README.md.hbs', dest: 'README.md', template: true },
25
+ // Workers — platform-usage (data warehouse, cron + queue consumer)
26
+ { src: 'shared/workers/platform-usage.ts', dest: 'workers/platform-usage.ts', template: false },
27
+ // Workers — root lib (shared utilities)
28
+ { src: 'shared/workers/lib/billing.ts', dest: 'workers/lib/billing.ts', template: false },
29
+ { src: 'shared/workers/lib/economics.ts', dest: 'workers/lib/economics.ts', template: false },
30
+ { src: 'shared/workers/lib/analytics-engine.ts', dest: 'workers/lib/analytics-engine.ts', template: false },
31
+ { src: 'shared/workers/lib/platform-settings.ts', dest: 'workers/lib/platform-settings.ts', template: false },
32
+ { src: 'shared/workers/lib/circuit-breaker-middleware.ts', dest: 'workers/lib/circuit-breaker-middleware.ts', template: false },
33
+ { src: 'shared/workers/lib/metrics.ts', dest: 'workers/lib/metrics.ts', template: false },
34
+ { src: 'shared/workers/lib/telemetry-sampling.ts', dest: 'workers/lib/telemetry-sampling.ts', template: false },
35
+ { src: 'shared/workers/lib/control.ts', dest: 'workers/lib/control.ts', template: false },
36
+ // Workers — lib/shared (cross-boundary types and utilities)
37
+ { src: 'shared/workers/lib/shared/types.ts', dest: 'workers/lib/shared/types.ts', template: false },
38
+ { src: 'shared/workers/lib/shared/allowances.ts', dest: 'workers/lib/shared/allowances.ts', template: false },
39
+ { src: 'shared/workers/lib/shared/cloudflare.ts', dest: 'workers/lib/shared/cloudflare.ts', template: false },
40
+ // Workers — lib/usage/shared
41
+ { src: 'shared/workers/lib/usage/shared/types.ts', dest: 'workers/lib/usage/shared/types.ts', template: false },
42
+ { src: 'shared/workers/lib/usage/shared/constants.ts', dest: 'workers/lib/usage/shared/constants.ts', template: false },
43
+ { src: 'shared/workers/lib/usage/shared/utils.ts', dest: 'workers/lib/usage/shared/utils.ts', template: false },
44
+ { src: 'shared/workers/lib/usage/shared/index.ts', dest: 'workers/lib/usage/shared/index.ts', template: false },
45
+ // Workers — lib/usage/handlers
46
+ { src: 'shared/workers/lib/usage/handlers/index.ts', dest: 'workers/lib/usage/handlers/index.ts', template: false },
47
+ { src: 'shared/workers/lib/usage/handlers/data-queries.ts', dest: 'workers/lib/usage/handlers/data-queries.ts', template: false },
48
+ { src: 'shared/workers/lib/usage/handlers/usage-metrics.ts', dest: 'workers/lib/usage/handlers/usage-metrics.ts', template: false },
49
+ { src: 'shared/workers/lib/usage/handlers/usage-features.ts', dest: 'workers/lib/usage/handlers/usage-features.ts', template: false },
50
+ { src: 'shared/workers/lib/usage/handlers/usage-settings.ts', dest: 'workers/lib/usage/handlers/usage-settings.ts', template: false },
51
+ { src: 'shared/workers/lib/usage/handlers/usage-admin.ts', dest: 'workers/lib/usage/handlers/usage-admin.ts', template: false },
52
+ { src: 'shared/workers/lib/usage/handlers/dlq-admin.ts', dest: 'workers/lib/usage/handlers/dlq-admin.ts', template: false },
53
+ { src: 'shared/workers/lib/usage/handlers/health-trends.ts', dest: 'workers/lib/usage/handlers/health-trends.ts', template: false },
54
+ { src: 'shared/workers/lib/usage/handlers/backfill.ts', dest: 'workers/lib/usage/handlers/backfill.ts', template: false },
55
+ { src: 'shared/workers/lib/usage/handlers/audit.ts', dest: 'workers/lib/usage/handlers/audit.ts', template: false },
56
+ { src: 'shared/workers/lib/usage/handlers/behavioral.ts', dest: 'workers/lib/usage/handlers/behavioral.ts', template: false },
57
+ // Workers — lib/usage/queue
58
+ { src: 'shared/workers/lib/usage/queue/index.ts', dest: 'workers/lib/usage/queue/index.ts', template: false },
59
+ { src: 'shared/workers/lib/usage/queue/telemetry-processor.ts', dest: 'workers/lib/usage/queue/telemetry-processor.ts', template: false },
60
+ { src: 'shared/workers/lib/usage/queue/dlq-handler.ts', dest: 'workers/lib/usage/queue/dlq-handler.ts', template: false },
61
+ { src: 'shared/workers/lib/usage/queue/budget-enforcement.ts', dest: 'workers/lib/usage/queue/budget-enforcement.ts', template: false },
62
+ { src: 'shared/workers/lib/usage/queue/cost-calculator.ts', dest: 'workers/lib/usage/queue/cost-calculator.ts', template: false },
63
+ { src: 'shared/workers/lib/usage/queue/cost-budget-enforcement.ts', dest: 'workers/lib/usage/queue/cost-budget-enforcement.ts', template: false },
64
+ // Workers — lib/usage/scheduled
65
+ { src: 'shared/workers/lib/usage/scheduled/index.ts', dest: 'workers/lib/usage/scheduled/index.ts', template: false },
66
+ { src: 'shared/workers/lib/usage/scheduled/data-collection.ts', dest: 'workers/lib/usage/scheduled/data-collection.ts', template: false },
67
+ { src: 'shared/workers/lib/usage/scheduled/anomaly-detection.ts', dest: 'workers/lib/usage/scheduled/anomaly-detection.ts', template: false },
68
+ { src: 'shared/workers/lib/usage/scheduled/rollups.ts', dest: 'workers/lib/usage/scheduled/rollups.ts', template: false },
69
+ { src: 'shared/workers/lib/usage/scheduled/error-digest.ts', dest: 'workers/lib/usage/scheduled/error-digest.ts', template: false },
70
+ // Workers — lib/usage/collectors (pluggable interface + example)
71
+ { src: 'shared/workers/lib/usage/collectors/index.ts', dest: 'workers/lib/usage/collectors/index.ts', template: false },
72
+ { src: 'shared/workers/lib/usage/collectors/example.ts', dest: 'workers/lib/usage/collectors/example.ts', template: false },
73
+ ];
74
+ const STANDARD_FILES = [
75
+ // Additional migrations
76
+ { src: 'standard/migrations/005_error_collection.sql', dest: 'storage/d1/migrations/005_error_collection.sql', template: false },
77
+ // Wrangler configs
78
+ { src: 'standard/wrangler.error-collector.jsonc.hbs', dest: 'wrangler.{{projectSlug}}-error-collector.jsonc', template: true },
79
+ { src: 'standard/wrangler.sentinel.jsonc.hbs', dest: 'wrangler.{{projectSlug}}-sentinel.jsonc', template: true },
80
+ // Workers — error-collector (tail worker → GitHub issues)
81
+ { src: 'standard/workers/error-collector.ts', dest: 'workers/error-collector.ts', template: false },
82
+ { src: 'standard/workers/lib/error-collector/capture.ts', dest: 'workers/lib/error-collector/capture.ts', template: false },
83
+ { src: 'standard/workers/lib/error-collector/fingerprint.ts', dest: 'workers/lib/error-collector/fingerprint.ts', template: false },
84
+ { src: 'standard/workers/lib/error-collector/types.ts', dest: 'workers/lib/error-collector/types.ts', template: false },
85
+ { src: 'standard/workers/lib/error-collector/github.ts', dest: 'workers/lib/error-collector/github.ts', template: false },
86
+ { src: 'standard/workers/lib/error-collector/digest.ts', dest: 'workers/lib/error-collector/digest.ts', template: false },
87
+ { src: 'standard/workers/lib/error-collector/gap-alerts.ts', dest: 'workers/lib/error-collector/gap-alerts.ts', template: false },
88
+ { src: 'standard/workers/lib/error-collector/email-health-alerts.ts', dest: 'workers/lib/error-collector/email-health-alerts.ts', template: false },
89
+ // Workers — platform-sentinel (gap detection, cost monitoring)
90
+ { src: 'standard/workers/platform-sentinel.ts', dest: 'workers/platform-sentinel.ts', template: false },
91
+ { src: 'standard/workers/lib/sentinel/gap-detection.ts', dest: 'workers/lib/sentinel/gap-detection.ts', template: false },
92
+ // Workers — shared lib (used by standard-tier workers)
93
+ { src: 'standard/workers/lib/shared/slack-alerts.ts', dest: 'workers/lib/shared/slack-alerts.ts', template: false },
94
+ ];
95
+ const FULL_FILES = [
96
+ // Additional migrations
97
+ { src: 'full/migrations/006_pattern_discovery.sql', dest: 'storage/d1/migrations/006_pattern_discovery.sql', template: false },
98
+ { src: 'full/migrations/007_notifications_search.sql', dest: 'storage/d1/migrations/007_notifications_search.sql', template: false },
99
+ // Wrangler configs
100
+ { src: 'full/wrangler.pattern-discovery.jsonc.hbs', dest: 'wrangler.{{projectSlug}}-pattern-discovery.jsonc', template: true },
101
+ { src: 'full/wrangler.alert-router.jsonc.hbs', dest: 'wrangler.{{projectSlug}}-alert-router.jsonc', template: true },
102
+ { src: 'full/wrangler.notifications.jsonc.hbs', dest: 'wrangler.{{projectSlug}}-notifications.jsonc', template: true },
103
+ { src: 'full/wrangler.search.jsonc.hbs', dest: 'wrangler.{{projectSlug}}-search.jsonc', template: true },
104
+ { src: 'full/wrangler.settings.jsonc.hbs', dest: 'wrangler.{{projectSlug}}-settings.jsonc', template: true },
105
+ // Workers — pattern-discovery (AI-assisted transient error patterns)
106
+ { src: 'full/workers/pattern-discovery.ts', dest: 'workers/pattern-discovery.ts', template: false },
107
+ { src: 'full/workers/lib/pattern-discovery/types.ts', dest: 'workers/lib/pattern-discovery/types.ts', template: false },
108
+ { src: 'full/workers/lib/pattern-discovery/clustering.ts', dest: 'workers/lib/pattern-discovery/clustering.ts', template: false },
109
+ { src: 'full/workers/lib/pattern-discovery/ai-prompt.ts', dest: 'workers/lib/pattern-discovery/ai-prompt.ts', template: false },
110
+ { src: 'full/workers/lib/pattern-discovery/storage.ts', dest: 'workers/lib/pattern-discovery/storage.ts', template: false },
111
+ { src: 'full/workers/lib/pattern-discovery/validation.ts', dest: 'workers/lib/pattern-discovery/validation.ts', template: false },
112
+ { src: 'full/workers/lib/pattern-discovery/shadow-evaluation.ts', dest: 'workers/lib/pattern-discovery/shadow-evaluation.ts', template: false },
113
+ // Workers — platform-alert-router (unified alert normalisation)
114
+ { src: 'full/workers/platform-alert-router.ts', dest: 'workers/platform-alert-router.ts', template: false },
115
+ // Workers — platform-notifications (in-app notification API)
116
+ { src: 'full/workers/platform-notifications.ts', dest: 'workers/platform-notifications.ts', template: false },
117
+ // Workers — platform-search (full-text search FTS5)
118
+ { src: 'full/workers/platform-search.ts', dest: 'workers/platform-search.ts', template: false },
119
+ // Workers — platform-settings (settings management API)
120
+ { src: 'full/workers/platform-settings.ts', dest: 'workers/platform-settings.ts', template: false },
121
+ ];
122
+ export function getFilesForTier(tier) {
123
+ const files = [...SHARED_FILES];
124
+ if (tier === 'standard' || tier === 'full') {
125
+ files.push(...STANDARD_FILES);
126
+ }
127
+ if (tier === 'full') {
128
+ files.push(...FULL_FILES);
129
+ }
130
+ return files;
131
+ }
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@littlebearapps/platform-admin-sdk",
3
+ "version": "1.0.0",
4
+ "description": "Platform Admin SDK — scaffold backend infrastructure with workers, circuit breakers, and cost protection for Cloudflare",
5
+ "type": "module",
6
+ "bin": {
7
+ "platform-admin-sdk": "./dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist/",
11
+ "templates/"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsc",
15
+ "test": "vitest run",
16
+ "typecheck": "tsc --noEmit",
17
+ "prepublishOnly": "npm run build"
18
+ },
19
+ "dependencies": {
20
+ "commander": "^14.0.3",
21
+ "handlebars": "^4.7.8",
22
+ "picocolors": "^1.1.1"
23
+ },
24
+ "devDependencies": {
25
+ "@types/node": "^22.0.0",
26
+ "typescript": "^5.7.3",
27
+ "vitest": "^3.0.5"
28
+ },
29
+ "publishConfig": {
30
+ "access": "public"
31
+ },
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "https://github.com/littlebearapps/platform-sdks.git",
35
+ "directory": "packages/admin-sdk"
36
+ },
37
+ "keywords": [
38
+ "cloudflare-workers",
39
+ "platform-admin-sdk",
40
+ "scaffold",
41
+ "cost-protection",
42
+ "circuit-breaker"
43
+ ],
44
+ "author": "Little Bear Apps",
45
+ "license": "MIT"
46
+ }