@butterbase/shared 0.2.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 (73) hide show
  1. package/dist/ai-router/index.d.ts +2 -0
  2. package/dist/ai-router/index.d.ts.map +1 -0
  3. package/dist/ai-router/index.js +2 -0
  4. package/dist/ai-router/index.js.map +1 -0
  5. package/dist/ai-router/router-adapter.d.ts +33 -0
  6. package/dist/ai-router/router-adapter.d.ts.map +1 -0
  7. package/dist/ai-router/router-adapter.js +2 -0
  8. package/dist/ai-router/router-adapter.js.map +1 -0
  9. package/dist/billing/billing-provider.d.ts +30 -0
  10. package/dist/billing/billing-provider.d.ts.map +1 -0
  11. package/dist/billing/billing-provider.js +15 -0
  12. package/dist/billing/billing-provider.js.map +1 -0
  13. package/dist/billing/billing-provider.test.d.ts +2 -0
  14. package/dist/billing/billing-provider.test.d.ts.map +1 -0
  15. package/dist/billing/billing-provider.test.js +20 -0
  16. package/dist/billing/billing-provider.test.js.map +1 -0
  17. package/dist/billing/index.d.ts +2 -0
  18. package/dist/billing/index.d.ts.map +1 -0
  19. package/dist/billing/index.js +2 -0
  20. package/dist/billing/index.js.map +1 -0
  21. package/dist/constants.d.ts +16 -0
  22. package/dist/constants.d.ts.map +1 -0
  23. package/dist/constants.js +16 -0
  24. package/dist/constants.js.map +1 -0
  25. package/dist/error-types.d.ts +104 -0
  26. package/dist/error-types.d.ts.map +1 -0
  27. package/dist/error-types.js +113 -0
  28. package/dist/error-types.js.map +1 -0
  29. package/dist/errors.d.ts +13 -0
  30. package/dist/errors.d.ts.map +1 -0
  31. package/dist/errors.js +25 -0
  32. package/dist/errors.js.map +1 -0
  33. package/dist/index.d.ts +11 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/index.js +11 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/index.test.d.ts +2 -0
  38. package/dist/index.test.d.ts.map +1 -0
  39. package/dist/index.test.js +19 -0
  40. package/dist/index.test.js.map +1 -0
  41. package/dist/quota/index.d.ts +2 -0
  42. package/dist/quota/index.d.ts.map +1 -0
  43. package/dist/quota/index.js +2 -0
  44. package/dist/quota/index.js.map +1 -0
  45. package/dist/quota/quota-enforcer.d.ts +26 -0
  46. package/dist/quota/quota-enforcer.d.ts.map +1 -0
  47. package/dist/quota/quota-enforcer.js +16 -0
  48. package/dist/quota/quota-enforcer.js.map +1 -0
  49. package/dist/quota/quota-enforcer.test.d.ts +2 -0
  50. package/dist/quota/quota-enforcer.test.d.ts.map +1 -0
  51. package/dist/quota/quota-enforcer.test.js +18 -0
  52. package/dist/quota/quota-enforcer.test.js.map +1 -0
  53. package/dist/regions.d.ts +21 -0
  54. package/dist/regions.d.ts.map +1 -0
  55. package/dist/regions.js +115 -0
  56. package/dist/regions.js.map +1 -0
  57. package/dist/regions.test.d.ts +2 -0
  58. package/dist/regions.test.d.ts.map +1 -0
  59. package/dist/regions.test.js +129 -0
  60. package/dist/regions.test.js.map +1 -0
  61. package/dist/response-types.d.ts +42 -0
  62. package/dist/response-types.d.ts.map +1 -0
  63. package/dist/response-types.js +3 -0
  64. package/dist/response-types.js.map +1 -0
  65. package/dist/schema-dsl.d.ts +28 -0
  66. package/dist/schema-dsl.d.ts.map +1 -0
  67. package/dist/schema-dsl.js +6 -0
  68. package/dist/schema-dsl.js.map +1 -0
  69. package/dist/types.d.ts +155 -0
  70. package/dist/types.d.ts.map +1 -0
  71. package/dist/types.js +3 -0
  72. package/dist/types.js.map +1 -0
  73. package/package.json +49 -0
@@ -0,0 +1,16 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ export class UnlimitedQuotaEnforcer {
3
+ async acquireLease(_userId, _req) {
4
+ return {
5
+ granted: true,
6
+ leaseId: randomUUID(),
7
+ budgetUsd: Number.POSITIVE_INFINITY,
8
+ expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000),
9
+ };
10
+ }
11
+ async settleLease(_leaseId, _params) { }
12
+ async getRemaining(_userId, _kind) {
13
+ return Number.POSITIVE_INFINITY;
14
+ }
15
+ }
16
+ //# sourceMappingURL=quota-enforcer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quota-enforcer.js","sourceRoot":"","sources":["../../src/quota/quota-enforcer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AA2BzC,MAAM,OAAO,sBAAsB;IACjC,KAAK,CAAC,YAAY,CAAC,OAAe,EAAE,IAAkB;QACpD,OAAO;YACL,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,UAAU,EAAE;YACrB,SAAS,EAAE,MAAM,CAAC,iBAAiB;YACnC,SAAS,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;SACtD,CAAC;IACJ,CAAC;IACD,KAAK,CAAC,WAAW,CAAC,QAAgB,EAAE,OAAqB,IAAkB,CAAC;IAC5E,KAAK,CAAC,YAAY,CAAC,OAAe,EAAE,KAAgB;QAClD,OAAO,MAAM,CAAC,iBAAiB,CAAC;IAClC,CAAC;CACF"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=quota-enforcer.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quota-enforcer.test.d.ts","sourceRoot":"","sources":["../../src/quota/quota-enforcer.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,18 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { UnlimitedQuotaEnforcer } from './index.js';
3
+ describe('UnlimitedQuotaEnforcer', () => {
4
+ const enforcer = new UnlimitedQuotaEnforcer();
5
+ it('always grants a lease', async () => {
6
+ const lease = await enforcer.acquireLease('user-123', { kind: 'ai_credits' });
7
+ expect(lease.granted).toBe(true);
8
+ expect(lease.leaseId).toBeTruthy();
9
+ });
10
+ it('settle is a no-op', async () => {
11
+ await expect(enforcer.settleLease('lease-abc', { actualUsdSpent: 0.5 })).resolves.toBeUndefined();
12
+ });
13
+ it('getRemaining returns Infinity', async () => {
14
+ const remaining = await enforcer.getRemaining('user-123', 'ai_credits');
15
+ expect(remaining).toBe(Infinity);
16
+ });
17
+ });
18
+ //# sourceMappingURL=quota-enforcer.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quota-enforcer.test.js","sourceRoot":"","sources":["../../src/quota/quota-enforcer.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,sBAAsB,EAAsB,MAAM,YAAY,CAAC;AAExE,QAAQ,CAAC,wBAAwB,EAAE,GAAG,EAAE;IACtC,MAAM,QAAQ,GAAkB,IAAI,sBAAsB,EAAE,CAAC;IAE7D,EAAE,CAAC,uBAAuB,EAAE,KAAK,IAAI,EAAE;QACrC,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,YAAY,CAAC,UAAU,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC;QAC9E,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mBAAmB,EAAE,KAAK,IAAI,EAAE;QACjC,MAAM,MAAM,CACV,QAAQ,CAAC,WAAW,CAAC,WAAW,EAAE,EAAE,cAAc,EAAE,GAAG,EAAE,CAAC,CAC3D,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC;IAC7B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+BAA+B,EAAE,KAAK,IAAI,EAAE;QAC7C,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,YAAY,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;QACxE,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,21 @@
1
+ export declare class RegionConfigError extends Error {
2
+ constructor(message: string);
3
+ }
4
+ export declare function parseRegions(raw: string): string[];
5
+ export declare function parseInstanceRegion(raw: string, allowed: string[]): string;
6
+ export interface RegionConfig {
7
+ regions: string[];
8
+ instanceRegion: string;
9
+ }
10
+ export declare function parseFlyRegionMap(raw: string): Record<string, string>;
11
+ export declare function loadRegionConfig(env: Record<string, string | undefined>): RegionConfig;
12
+ export declare function regionToEnvSuffix(region: string): string;
13
+ /**
14
+ * Given an AWS-style butterbase region (e.g. "us-west-2"), return the first
15
+ * Fly region code (e.g. "sjc") configured to serve it via BUTTERBASE_FLY_REGION_MAP.
16
+ * Fly load-balances across machines within the chosen fly region, so picking
17
+ * the first match is sufficient. Returns null when no fly region maps to the
18
+ * given butterbase region.
19
+ */
20
+ export declare function butterbaseRegionToFlyRegion(butterbaseRegion: string, flyRegionMap: Record<string, string>): string | null;
21
+ //# sourceMappingURL=regions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"regions.d.ts","sourceRoot":"","sources":["../src/regions.ts"],"names":[],"mappings":"AAAA,qBAAa,iBAAkB,SAAQ,KAAK;gBAC9B,OAAO,EAAE,MAAM;CAI5B;AAID,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAwBlD;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,CAW1E;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAyBrE;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,YAAY,CAqCtF;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CACzC,gBAAgB,EAAE,MAAM,EACxB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACnC,MAAM,GAAG,IAAI,CAKf"}
@@ -0,0 +1,115 @@
1
+ export class RegionConfigError extends Error {
2
+ constructor(message) {
3
+ super(message);
4
+ this.name = 'RegionConfigError';
5
+ }
6
+ }
7
+ const REGION_PATTERN = /^[a-z]+(-[a-z0-9]+)+$/;
8
+ export function parseRegions(raw) {
9
+ const trimmed = raw.trim();
10
+ if (!trimmed) {
11
+ throw new RegionConfigError('BUTTERBASE_REGIONS is empty');
12
+ }
13
+ const items = trimmed.split(',').map((s) => s.trim()).filter(Boolean);
14
+ if (items.length === 0) {
15
+ throw new RegionConfigError('BUTTERBASE_REGIONS contained no usable values');
16
+ }
17
+ for (const item of items) {
18
+ if (!REGION_PATTERN.test(item)) {
19
+ throw new RegionConfigError(`Invalid region "${item}". Expected lowercase, hyphen-separated (e.g. us-east-1).`);
20
+ }
21
+ }
22
+ const seen = new Set();
23
+ for (const item of items) {
24
+ if (seen.has(item)) {
25
+ throw new RegionConfigError(`Duplicate region in BUTTERBASE_REGIONS: ${item}`);
26
+ }
27
+ seen.add(item);
28
+ }
29
+ return items;
30
+ }
31
+ export function parseInstanceRegion(raw, allowed) {
32
+ const trimmed = raw.trim();
33
+ if (!trimmed) {
34
+ throw new RegionConfigError('BUTTERBASE_REGION is empty');
35
+ }
36
+ if (!allowed.includes(trimmed)) {
37
+ throw new RegionConfigError(`BUTTERBASE_REGION "${trimmed}" is not in BUTTERBASE_REGIONS [${allowed.join(',')}]`);
38
+ }
39
+ return trimmed;
40
+ }
41
+ export function parseFlyRegionMap(raw) {
42
+ const trimmed = raw.trim();
43
+ if (!trimmed) {
44
+ throw new RegionConfigError('BUTTERBASE_FLY_REGION_MAP is empty');
45
+ }
46
+ const entries = trimmed.split(',').map((s) => s.trim()).filter(Boolean);
47
+ const map = {};
48
+ for (const entry of entries) {
49
+ const idx = entry.indexOf(':');
50
+ if (idx <= 0 || idx === entry.length - 1) {
51
+ throw new RegionConfigError(`Malformed entry "${entry}" in BUTTERBASE_FLY_REGION_MAP. Expected format: <fly_region>:<butterbase_region>`);
52
+ }
53
+ const flyRegion = entry.slice(0, idx).trim();
54
+ const butterbaseRegion = entry.slice(idx + 1).trim();
55
+ if (!flyRegion || !butterbaseRegion) {
56
+ throw new RegionConfigError(`Empty key or value in entry "${entry}"`);
57
+ }
58
+ if (map[flyRegion] !== undefined) {
59
+ throw new RegionConfigError(`Duplicate Fly region key "${flyRegion}" in BUTTERBASE_FLY_REGION_MAP`);
60
+ }
61
+ map[flyRegion] = butterbaseRegion;
62
+ }
63
+ return map;
64
+ }
65
+ export function loadRegionConfig(env) {
66
+ const regionsRaw = env.BUTTERBASE_REGIONS;
67
+ if (regionsRaw === undefined) {
68
+ throw new RegionConfigError('BUTTERBASE_REGIONS env var is not set');
69
+ }
70
+ const regions = parseRegions(regionsRaw);
71
+ // Resolution order:
72
+ // 1. Explicit BUTTERBASE_REGION (operator override / local dev)
73
+ // 2. Derive from FLY_REGION via BUTTERBASE_FLY_REGION_MAP (production on Fly)
74
+ let instanceRegion;
75
+ const explicit = env.BUTTERBASE_REGION;
76
+ if (explicit !== undefined) {
77
+ const stripped = explicit.trim();
78
+ if (!stripped) {
79
+ throw new RegionConfigError('BUTTERBASE_REGION is set but empty');
80
+ }
81
+ instanceRegion = parseInstanceRegion(stripped, regions);
82
+ }
83
+ else {
84
+ const flyRegion = env.FLY_REGION;
85
+ const mapRaw = env.BUTTERBASE_FLY_REGION_MAP;
86
+ if (!flyRegion || !mapRaw) {
87
+ throw new RegionConfigError('BUTTERBASE_REGION env var is not set, and no FLY_REGION + BUTTERBASE_FLY_REGION_MAP available to derive from');
88
+ }
89
+ const map = parseFlyRegionMap(mapRaw);
90
+ const derived = map[flyRegion];
91
+ if (!derived) {
92
+ throw new RegionConfigError(`FLY_REGION "${flyRegion}" has no entry in BUTTERBASE_FLY_REGION_MAP`);
93
+ }
94
+ instanceRegion = parseInstanceRegion(derived, regions);
95
+ }
96
+ return { regions, instanceRegion };
97
+ }
98
+ export function regionToEnvSuffix(region) {
99
+ return region.toUpperCase().replace(/-/g, '_');
100
+ }
101
+ /**
102
+ * Given an AWS-style butterbase region (e.g. "us-west-2"), return the first
103
+ * Fly region code (e.g. "sjc") configured to serve it via BUTTERBASE_FLY_REGION_MAP.
104
+ * Fly load-balances across machines within the chosen fly region, so picking
105
+ * the first match is sufficient. Returns null when no fly region maps to the
106
+ * given butterbase region.
107
+ */
108
+ export function butterbaseRegionToFlyRegion(butterbaseRegion, flyRegionMap) {
109
+ for (const [fly, bb] of Object.entries(flyRegionMap)) {
110
+ if (bb === butterbaseRegion)
111
+ return fly;
112
+ }
113
+ return null;
114
+ }
115
+ //# sourceMappingURL=regions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"regions.js","sourceRoot":"","sources":["../src/regions.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAC1C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF;AAED,MAAM,cAAc,GAAG,uBAAuB,CAAC;AAE/C,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAC3B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,iBAAiB,CAAC,6BAA6B,CAAC,CAAC;IAC7D,CAAC;IACD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACtE,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,iBAAiB,CAAC,+CAA+C,CAAC,CAAC;IAC/E,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC/B,MAAM,IAAI,iBAAiB,CACzB,mBAAmB,IAAI,2DAA2D,CACnF,CAAC;QACJ,CAAC;IACH,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACnB,MAAM,IAAI,iBAAiB,CAAC,2CAA2C,IAAI,EAAE,CAAC,CAAC;QACjF,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACjB,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,GAAW,EAAE,OAAiB;IAChE,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAC3B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,iBAAiB,CAAC,4BAA4B,CAAC,CAAC;IAC5D,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,iBAAiB,CACzB,sBAAsB,OAAO,mCAAmC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CACrF,CAAC;IACJ,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAOD,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAC3C,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAC3B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,iBAAiB,CAAC,oCAAoC,CAAC,CAAC;IACpE,CAAC;IACD,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACxE,MAAM,GAAG,GAA2B,EAAE,CAAC;IACvC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC/B,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,KAAK,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzC,MAAM,IAAI,iBAAiB,CACzB,oBAAoB,KAAK,mFAAmF,CAC7G,CAAC;QACJ,CAAC;QACD,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;QAC7C,MAAM,gBAAgB,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACrD,IAAI,CAAC,SAAS,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACpC,MAAM,IAAI,iBAAiB,CAAC,gCAAgC,KAAK,GAAG,CAAC,CAAC;QACxE,CAAC;QACD,IAAI,GAAG,CAAC,SAAS,CAAC,KAAK,SAAS,EAAE,CAAC;YACjC,MAAM,IAAI,iBAAiB,CAAC,6BAA6B,SAAS,gCAAgC,CAAC,CAAC;QACtG,CAAC;QACD,GAAG,CAAC,SAAS,CAAC,GAAG,gBAAgB,CAAC;IACpC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,GAAuC;IACtE,MAAM,UAAU,GAAG,GAAG,CAAC,kBAAkB,CAAC;IAC1C,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC7B,MAAM,IAAI,iBAAiB,CAAC,uCAAuC,CAAC,CAAC;IACvE,CAAC;IACD,MAAM,OAAO,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC;IAEzC,oBAAoB;IACpB,kEAAkE;IAClE,gFAAgF;IAChF,IAAI,cAAsB,CAAC;IAC3B,MAAM,QAAQ,GAAG,GAAG,CAAC,iBAAiB,CAAC;IACvC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;QACjC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,iBAAiB,CAAC,oCAAoC,CAAC,CAAC;QACpE,CAAC;QACD,cAAc,GAAG,mBAAmB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC1D,CAAC;SAAM,CAAC;QACN,MAAM,SAAS,GAAG,GAAG,CAAC,UAAU,CAAC;QACjC,MAAM,MAAM,GAAG,GAAG,CAAC,yBAAyB,CAAC;QAC7C,IAAI,CAAC,SAAS,IAAI,CAAC,MAAM,EAAE,CAAC;YAC1B,MAAM,IAAI,iBAAiB,CACzB,8GAA8G,CAC/G,CAAC;QACJ,CAAC;QACD,MAAM,GAAG,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;QACtC,MAAM,OAAO,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC;QAC/B,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,iBAAiB,CACzB,eAAe,SAAS,6CAA6C,CACtE,CAAC;QACJ,CAAC;QACD,cAAc,GAAG,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACzD,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,MAAc;IAC9C,OAAO,MAAM,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AACjD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,2BAA2B,CACzC,gBAAwB,EACxB,YAAoC;IAEpC,KAAK,MAAM,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;QACrD,IAAI,EAAE,KAAK,gBAAgB;YAAE,OAAO,GAAG,CAAC;IAC1C,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=regions.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"regions.test.d.ts","sourceRoot":"","sources":["../src/regions.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,129 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { parseRegions, parseInstanceRegion, loadRegionConfig, RegionConfigError } from './regions.js';
3
+ describe('parseRegions', () => {
4
+ it('parses a comma-separated list, trimming whitespace', () => {
5
+ expect(parseRegions('us-east-1, eu-west-1, ap-southeast-1')).toEqual([
6
+ 'us-east-1',
7
+ 'eu-west-1',
8
+ 'ap-southeast-1',
9
+ ]);
10
+ });
11
+ it('parses a single-region list', () => {
12
+ expect(parseRegions('us-east-1')).toEqual(['us-east-1']);
13
+ });
14
+ it('throws on empty input', () => {
15
+ expect(() => parseRegions('')).toThrow(RegionConfigError);
16
+ expect(() => parseRegions(' ')).toThrow(RegionConfigError);
17
+ });
18
+ it('throws on duplicate regions', () => {
19
+ expect(() => parseRegions('us-east-1,us-east-1')).toThrow(/duplicate/i);
20
+ });
21
+ it('throws on invalid format', () => {
22
+ expect(() => parseRegions('US_EAST_1')).toThrow(/lowercase/i);
23
+ expect(() => parseRegions('us east 1')).toThrow();
24
+ });
25
+ });
26
+ describe('parseInstanceRegion', () => {
27
+ it('returns the region when present in the allowed list', () => {
28
+ expect(parseInstanceRegion('us-east-1', ['us-east-1', 'eu-west-1'])).toEqual('us-east-1');
29
+ });
30
+ it('throws when region is not in the allowed list', () => {
31
+ expect(() => parseInstanceRegion('eu-west-1', ['us-east-1'])).toThrow(/not in BUTTERBASE_REGIONS/);
32
+ });
33
+ it('throws on empty input', () => {
34
+ expect(() => parseInstanceRegion('', ['us-east-1'])).toThrow(RegionConfigError);
35
+ });
36
+ });
37
+ describe('loadRegionConfig', () => {
38
+ it('returns regions and instanceRegion when env is well-formed', () => {
39
+ const cfg = loadRegionConfig({
40
+ BUTTERBASE_REGIONS: 'us-east-1,eu-west-1',
41
+ BUTTERBASE_REGION: 'us-east-1',
42
+ });
43
+ expect(cfg).toEqual({ regions: ['us-east-1', 'eu-west-1'], instanceRegion: 'us-east-1' });
44
+ });
45
+ it('throws when BUTTERBASE_REGIONS is missing', () => {
46
+ expect(() => loadRegionConfig({ BUTTERBASE_REGION: 'us-east-1' })).toThrow(/BUTTERBASE_REGIONS/);
47
+ });
48
+ it('throws when BUTTERBASE_REGION is missing', () => {
49
+ expect(() => loadRegionConfig({ BUTTERBASE_REGIONS: 'us-east-1' })).toThrow(/BUTTERBASE_REGION/);
50
+ });
51
+ it('throws when instance region is not in the list', () => {
52
+ expect(() => loadRegionConfig({ BUTTERBASE_REGIONS: 'us-east-1', BUTTERBASE_REGION: 'eu-west-1' })).toThrow(/not in BUTTERBASE_REGIONS/);
53
+ });
54
+ });
55
+ describe('regionToEnvSuffix', () => {
56
+ it('uppercases and replaces hyphens with underscores', async () => {
57
+ const { regionToEnvSuffix } = await import('./regions.js');
58
+ expect(regionToEnvSuffix('us-east-1')).toEqual('US_EAST_1');
59
+ expect(regionToEnvSuffix('eu-west-1')).toEqual('EU_WEST_1');
60
+ });
61
+ });
62
+ describe('parseFlyRegionMap', () => {
63
+ it('parses a comma-separated map', async () => {
64
+ const { parseFlyRegionMap } = await import('./regions.js');
65
+ expect(parseFlyRegionMap('iad:us-east-1,lhr:eu-west-1')).toEqual({
66
+ iad: 'us-east-1',
67
+ lhr: 'eu-west-1',
68
+ });
69
+ });
70
+ it('throws on malformed entry', async () => {
71
+ const { parseFlyRegionMap, RegionConfigError } = await import('./regions.js');
72
+ expect(() => parseFlyRegionMap('iad-us-east-1')).toThrow(RegionConfigError);
73
+ expect(() => parseFlyRegionMap('iad:')).toThrow(RegionConfigError);
74
+ expect(() => parseFlyRegionMap(':us-east-1')).toThrow(RegionConfigError);
75
+ });
76
+ it('throws on empty input', async () => {
77
+ const { parseFlyRegionMap, RegionConfigError } = await import('./regions.js');
78
+ expect(() => parseFlyRegionMap('')).toThrow(RegionConfigError);
79
+ });
80
+ it('throws on duplicate Fly region keys', async () => {
81
+ const { parseFlyRegionMap } = await import('./regions.js');
82
+ expect(() => parseFlyRegionMap('iad:us-east-1,iad:us-east-2')).toThrow(/duplicate/i);
83
+ });
84
+ });
85
+ describe('loadRegionConfig with FLY_REGION derivation', () => {
86
+ it('derives instanceRegion from FLY_REGION + BUTTERBASE_FLY_REGION_MAP when BUTTERBASE_REGION is unset', () => {
87
+ const cfg = loadRegionConfig({
88
+ BUTTERBASE_REGIONS: 'us-east-1,eu-west-1',
89
+ BUTTERBASE_FLY_REGION_MAP: 'iad:us-east-1,lhr:eu-west-1',
90
+ FLY_REGION: 'lhr',
91
+ });
92
+ expect(cfg.instanceRegion).toEqual('eu-west-1');
93
+ });
94
+ it('prefers explicit BUTTERBASE_REGION over derivation', () => {
95
+ const cfg = loadRegionConfig({
96
+ BUTTERBASE_REGIONS: 'us-east-1,eu-west-1',
97
+ BUTTERBASE_REGION: 'us-east-1',
98
+ BUTTERBASE_FLY_REGION_MAP: 'iad:us-east-1,lhr:eu-west-1',
99
+ FLY_REGION: 'lhr',
100
+ });
101
+ expect(cfg.instanceRegion).toEqual('us-east-1');
102
+ });
103
+ it('throws when FLY_REGION is set but no map entry exists', () => {
104
+ expect(() => loadRegionConfig({
105
+ BUTTERBASE_REGIONS: 'us-east-1,eu-west-1',
106
+ BUTTERBASE_FLY_REGION_MAP: 'iad:us-east-1',
107
+ FLY_REGION: 'lhr',
108
+ })).toThrow(/FLY_REGION "lhr" has no entry in BUTTERBASE_FLY_REGION_MAP/);
109
+ });
110
+ it('throws when neither BUTTERBASE_REGION nor (FLY_REGION + map) is provided', () => {
111
+ expect(() => loadRegionConfig({ BUTTERBASE_REGIONS: 'us-east-1' })).toThrow(/BUTTERBASE_REGION/);
112
+ });
113
+ it('derived instanceRegion must still be in BUTTERBASE_REGIONS', () => {
114
+ expect(() => loadRegionConfig({
115
+ BUTTERBASE_REGIONS: 'us-east-1',
116
+ BUTTERBASE_FLY_REGION_MAP: 'lhr:eu-west-1',
117
+ FLY_REGION: 'lhr',
118
+ })).toThrow(/not in BUTTERBASE_REGIONS/);
119
+ });
120
+ it('throws when BUTTERBASE_REGION is set but empty (does not silently fall through to FLY_REGION)', () => {
121
+ expect(() => loadRegionConfig({
122
+ BUTTERBASE_REGIONS: 'us-east-1,eu-west-1',
123
+ BUTTERBASE_REGION: '',
124
+ BUTTERBASE_FLY_REGION_MAP: 'iad:us-east-1,lhr:eu-west-1',
125
+ FLY_REGION: 'lhr',
126
+ })).toThrow(/BUTTERBASE_REGION is set but empty/);
127
+ });
128
+ });
129
+ //# sourceMappingURL=regions.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"regions.test.js","sourceRoot":"","sources":["../src/regions.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Next action suggestion for agents
3
+ */
4
+ export interface NextAction {
5
+ action: string;
6
+ description: string;
7
+ recommended: boolean;
8
+ }
9
+ /**
10
+ * Resource usage information
11
+ */
12
+ export interface ResourceInfo {
13
+ quota_used?: number;
14
+ quota_limit?: number;
15
+ rate_limit_remaining?: number;
16
+ /** Storage used in bytes */
17
+ storage_used_bytes?: number;
18
+ /** Storage limit in bytes */
19
+ storage_limit_bytes?: number;
20
+ /** Storage used as percentage (0-100) */
21
+ storage_used_percent?: number;
22
+ /** Number of files stored */
23
+ files_count?: number;
24
+ /** Number of tables in database */
25
+ tables_count?: number;
26
+ /** Maximum tables allowed */
27
+ tables_limit?: number;
28
+ }
29
+ /**
30
+ * Response metadata for agent guidance
31
+ */
32
+ export interface ResponseMetadata {
33
+ next_actions?: NextAction[];
34
+ resource_info?: ResourceInfo;
35
+ }
36
+ /**
37
+ * Generic response wrapper with metadata
38
+ */
39
+ export type ResponseWithMetadata<T> = T & {
40
+ _meta?: ResponseMetadata;
41
+ };
42
+ //# sourceMappingURL=response-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"response-types.d.ts","sourceRoot":"","sources":["../src/response-types.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,4BAA4B;IAC5B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,6BAA6B;IAC7B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,yCAAyC;IACzC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,6BAA6B;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mCAAmC;IACnC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,6BAA6B;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,YAAY,CAAC,EAAE,UAAU,EAAE,CAAC;IAC5B,aAAa,CAAC,EAAE,YAAY,CAAC;CAC9B;AAED;;GAEG;AACH,MAAM,MAAM,oBAAoB,CAAC,CAAC,IAAI,CAAC,GAAG;IAAE,KAAK,CAAC,EAAE,gBAAgB,CAAC;CAAE,CAAA"}
@@ -0,0 +1,3 @@
1
+ // packages/shared/src/response-types.ts
2
+ export {};
3
+ //# sourceMappingURL=response-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"response-types.js","sourceRoot":"","sources":["../src/response-types.ts"],"names":[],"mappings":"AAAA,wCAAwC"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Schema DSL types for Butterbase declarative schema management.
3
+ * These types represent the desired state of an app's database schema.
4
+ */
5
+ export interface ColumnDef {
6
+ type: string;
7
+ primaryKey?: boolean;
8
+ nullable?: boolean;
9
+ default?: string;
10
+ unique?: boolean;
11
+ references?: string;
12
+ }
13
+ export interface IndexDef {
14
+ columns: string[];
15
+ unique?: boolean;
16
+ method?: string;
17
+ opclass?: string;
18
+ }
19
+ export interface TableDef {
20
+ columns: Record<string, ColumnDef>;
21
+ indexes?: Record<string, IndexDef>;
22
+ _dropColumns?: string[];
23
+ }
24
+ export interface SchemaDSL {
25
+ tables: Record<string, TableDef>;
26
+ _drop?: string[];
27
+ }
28
+ //# sourceMappingURL=schema-dsl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-dsl.d.ts","sourceRoot":"","sources":["../src/schema-dsl.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACnC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Schema DSL types for Butterbase declarative schema management.
3
+ * These types represent the desired state of an app's database schema.
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=schema-dsl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-dsl.js","sourceRoot":"","sources":["../src/schema-dsl.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
@@ -0,0 +1,155 @@
1
+ export interface PlatformUser {
2
+ id: string;
3
+ email: string;
4
+ password_hash: string;
5
+ display_name: string | null;
6
+ created_at: Date;
7
+ updated_at: Date;
8
+ }
9
+ export interface App {
10
+ id: string;
11
+ name: string;
12
+ owner_id: string;
13
+ db_name: string;
14
+ db_provisioned: boolean;
15
+ region: string;
16
+ created_at: Date;
17
+ updated_at: Date;
18
+ }
19
+ export interface AppUser {
20
+ id: string;
21
+ app_id: string;
22
+ email: string;
23
+ password_hash: string | null;
24
+ provider: string;
25
+ provider_uid: string | null;
26
+ metadata: Record<string, unknown>;
27
+ email_verified: boolean;
28
+ display_name: string | null;
29
+ avatar_url: string | null;
30
+ last_sign_in_at: Date | null;
31
+ created_at: Date;
32
+ updated_at: Date;
33
+ }
34
+ export interface StorageObject {
35
+ id: string;
36
+ app_id: string;
37
+ bucket: string;
38
+ key: string;
39
+ size_bytes: number | null;
40
+ mime_type: string | null;
41
+ metadata: Record<string, unknown>;
42
+ created_at: Date;
43
+ }
44
+ export interface AiUsageLog {
45
+ id: string;
46
+ app_id: string;
47
+ model: string;
48
+ provider: string;
49
+ prompt_tokens: number;
50
+ completion_tokens: number;
51
+ total_tokens: number;
52
+ cost_usd: number | null;
53
+ request_metadata: Record<string, unknown>;
54
+ created_at: Date;
55
+ }
56
+ export interface InitRequest {
57
+ name: string;
58
+ owner_id?: string;
59
+ }
60
+ export interface InitResponse {
61
+ app_id: string;
62
+ name: string;
63
+ database: {
64
+ host: string;
65
+ port: number;
66
+ name: string;
67
+ user: string;
68
+ connection_string: string;
69
+ };
70
+ api_url: string;
71
+ created_at: string;
72
+ _meta?: {
73
+ next_actions?: Array<{
74
+ action: string;
75
+ description: string;
76
+ recommended: boolean;
77
+ }>;
78
+ };
79
+ }
80
+ export interface ApiKey {
81
+ id: string;
82
+ user_id: string;
83
+ key_prefix: string;
84
+ name: string;
85
+ scopes: string[];
86
+ last_used_at?: Date;
87
+ expires_at?: Date;
88
+ revoked_at?: Date;
89
+ created_at: Date;
90
+ }
91
+ export interface AuthContext {
92
+ userId: string | null;
93
+ authMethod: 'api_key' | 'jwt' | 'end_user_jwt' | 'anonymous';
94
+ scopes: string[];
95
+ keyId?: string;
96
+ email?: string;
97
+ appId?: string;
98
+ rawToken?: string;
99
+ }
100
+ export interface AppSigningKey {
101
+ id: string;
102
+ app_id: string;
103
+ kid: string;
104
+ algorithm: string;
105
+ private_key_encrypted: string;
106
+ public_key: string;
107
+ active: boolean;
108
+ created_at: Date;
109
+ }
110
+ export interface AppOAuthConfig {
111
+ id: string;
112
+ app_id: string;
113
+ provider: string;
114
+ client_id: string;
115
+ client_secret_encrypted: string | null;
116
+ scopes: string[];
117
+ authorization_url: string | null;
118
+ token_url: string | null;
119
+ userinfo_url: string | null;
120
+ enabled: boolean;
121
+ }
122
+ export interface AppRefreshToken {
123
+ id: string;
124
+ app_id: string;
125
+ user_id: string;
126
+ token_hash: string;
127
+ expires_at: Date;
128
+ revoked_at: Date | null;
129
+ }
130
+ export interface EndUserClaims {
131
+ sub: string;
132
+ email: string;
133
+ email_verified: boolean;
134
+ app_id: string;
135
+ iat: number;
136
+ exp: number;
137
+ iss: string;
138
+ }
139
+ export interface EndUserAuthContext {
140
+ userId: string;
141
+ appId: string;
142
+ email: string;
143
+ emailVerified: boolean;
144
+ }
145
+ export interface RealtimeEvent {
146
+ type: 'change';
147
+ table: string;
148
+ op: 'INSERT' | 'UPDATE' | 'DELETE';
149
+ record: Record<string, unknown> | null;
150
+ old_record: Record<string, unknown> | null;
151
+ timestamp: string;
152
+ }
153
+ export * from './error-types.js';
154
+ export * from './response-types.js';
155
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ export * from './error-types.js';
2
+ export * from './response-types.js';
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAuKA,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC"}