@everystack/server 0.2.9 → 0.2.11
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/package.json +1 -1
- package/src/db.ts +41 -5
- package/src/plugin.ts +4 -0
- package/src/sst-env.d.ts +9 -3
package/package.json
CHANGED
package/src/db.ts
CHANGED
|
@@ -1,21 +1,57 @@
|
|
|
1
1
|
/// <reference path="./sst-env.d.ts" />
|
|
2
2
|
/**
|
|
3
|
-
* @everystack/server/db —
|
|
3
|
+
* @everystack/server/db — Database and secret helpers.
|
|
4
4
|
*
|
|
5
|
-
* Provides a lazy singleton Drizzle connection
|
|
6
|
-
*
|
|
5
|
+
* Provides a lazy singleton Drizzle connection. Supports both SST Resource
|
|
6
|
+
* linking (PascalCase names) and process.env (SCREAMING_SNAKE_CASE names)
|
|
7
|
+
* transparently. Works with createSecrets() or manual sst.Secret declarations.
|
|
7
8
|
*/
|
|
8
9
|
|
|
9
10
|
import { Resource } from 'sst';
|
|
10
11
|
import { drizzle } from 'drizzle-orm/postgres-js';
|
|
11
12
|
import postgres from 'postgres';
|
|
12
13
|
|
|
14
|
+
/**
|
|
15
|
+
* Safely read a Resource property. Returns undefined if the Resource
|
|
16
|
+
* or property doesn't exist (avoids runtime throw from SST's proxy).
|
|
17
|
+
*/
|
|
18
|
+
function tryResource<T>(fn: () => T): T | undefined {
|
|
19
|
+
try {
|
|
20
|
+
const val = fn();
|
|
21
|
+
// SST's Resource proxy may return undefined for missing keys
|
|
22
|
+
return val === undefined ? undefined : val;
|
|
23
|
+
} catch {
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
13
28
|
export function getDatabaseUrl(): string {
|
|
14
|
-
|
|
29
|
+
// SST Postgres component (Resource.Database)
|
|
30
|
+
const db = tryResource(() => Resource.Database);
|
|
31
|
+
if (db?.host) {
|
|
32
|
+
return `postgresql://${db.username}:${db.password}@${db.host}:${db.port}/${db.database}`;
|
|
33
|
+
}
|
|
34
|
+
// SST Secret — PascalCase (Resource.DatabaseUrl.value)
|
|
35
|
+
const pascal = tryResource(() => (Resource as any).DatabaseUrl?.value as string);
|
|
36
|
+
if (pascal) return pascal;
|
|
37
|
+
// SST Secret — raw env name (Resource.DATABASE_URL.value)
|
|
38
|
+
const raw = tryResource(() => (Resource as any).DATABASE_URL?.value as string);
|
|
39
|
+
if (raw) return raw;
|
|
40
|
+
// process.env fallback
|
|
41
|
+
if (process.env.DATABASE_URL) return process.env.DATABASE_URL;
|
|
42
|
+
throw new Error('DATABASE_URL not set — link an sst.aws.Postgres or sst.Secret, or set process.env.DATABASE_URL');
|
|
15
43
|
}
|
|
16
44
|
|
|
17
45
|
export function getJwtSecret(): Uint8Array {
|
|
18
|
-
|
|
46
|
+
// PascalCase Resource (Resource.JwtSecret.value)
|
|
47
|
+
const pascal = tryResource(() => (Resource as any).JwtSecret?.value as string);
|
|
48
|
+
if (pascal) return new TextEncoder().encode(pascal);
|
|
49
|
+
// Raw env name Resource (Resource.JWT_SECRET.value)
|
|
50
|
+
const raw = tryResource(() => (Resource as any).JWT_SECRET?.value as string);
|
|
51
|
+
if (raw) return new TextEncoder().encode(raw);
|
|
52
|
+
// process.env fallback
|
|
53
|
+
if (process.env.JWT_SECRET) return new TextEncoder().encode(process.env.JWT_SECRET);
|
|
54
|
+
throw new Error('JWT_SECRET not set — link an sst.Secret or set process.env.JWT_SECRET');
|
|
19
55
|
}
|
|
20
56
|
|
|
21
57
|
// Lazy singleton DB connection
|
package/src/plugin.ts
CHANGED
|
@@ -466,9 +466,13 @@ export function dbPlugin(options: DbPluginOptions): Plugin {
|
|
|
466
466
|
const { eq, and, or, gt, lt, gte, lte, ne, count, sum, avg, sql, desc, asc } =
|
|
467
467
|
await import('drizzle-orm');
|
|
468
468
|
const evalContext: Record<string, unknown> = {
|
|
469
|
+
ctx,
|
|
469
470
|
db: ctx.db, schema: ctx.schema,
|
|
470
471
|
eq, and, or, gt, lt, gte, lte, ne, count, sum, avg, sql, desc, asc,
|
|
471
472
|
};
|
|
473
|
+
// Expose plugin-contributed context (notifications, rpc, etc.)
|
|
474
|
+
if (ctx.notifications) evalContext.notifications = ctx.notifications;
|
|
475
|
+
if (ctx.rpc) evalContext.rpc = ctx.rpc;
|
|
472
476
|
const AsyncFunction = Object.getPrototypeOf(async function(){}).constructor;
|
|
473
477
|
const fn = new AsyncFunction(
|
|
474
478
|
...Object.keys(evalContext),
|
package/src/sst-env.d.ts
CHANGED
|
@@ -4,9 +4,14 @@
|
|
|
4
4
|
/**
|
|
5
5
|
* SST Resource type declarations for @everystack/server/db.
|
|
6
6
|
*
|
|
7
|
-
* Augments the `sst` module's Resource interface with
|
|
8
|
-
*
|
|
9
|
-
* (
|
|
7
|
+
* Augments the `sst` module's Resource interface with shapes expected
|
|
8
|
+
* by db.ts. Both PascalCase (JwtSecret) and SCREAMING_SNAKE_CASE
|
|
9
|
+
* (JWT_SECRET) naming conventions are supported at runtime — db.ts
|
|
10
|
+
* tries each in order and falls back to process.env.
|
|
11
|
+
*
|
|
12
|
+
* Consumers link matching SST resources in sst.config.ts:
|
|
13
|
+
* - sst.aws.Postgres named "Database"
|
|
14
|
+
* - sst.Secret named "JwtSecret" or "JWT_SECRET"
|
|
10
15
|
*/
|
|
11
16
|
declare module 'sst' {
|
|
12
17
|
export interface Resource {
|
|
@@ -20,6 +25,7 @@ declare module 'sst' {
|
|
|
20
25
|
JwtSecret: {
|
|
21
26
|
value: string;
|
|
22
27
|
};
|
|
28
|
+
[key: string]: any;
|
|
23
29
|
}
|
|
24
30
|
}
|
|
25
31
|
|