@omg-dev/server 0.4.41 → 0.4.42
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/dist/index.mjs +17 -1
- package/package.json +4 -4
- package/src/billing.ts +19 -0
- package/src/ctx.ts +5 -0
- package/src/index.ts +29 -0
package/dist/index.mjs
CHANGED
|
@@ -21,6 +21,9 @@ const ctx = {
|
|
|
21
21
|
},
|
|
22
22
|
get appId() {
|
|
23
23
|
return ctxStore.getStore()?.appId;
|
|
24
|
+
},
|
|
25
|
+
get request() {
|
|
26
|
+
return ctxStore.getStore()?.request;
|
|
24
27
|
}
|
|
25
28
|
};
|
|
26
29
|
//#endregion
|
|
@@ -2998,6 +3001,14 @@ const billing = {
|
|
|
2998
3001
|
return agentGet(`/_billing/subscription?${new URLSearchParams({ externalRef }).toString()}`, "subscription");
|
|
2999
3002
|
},
|
|
3000
3003
|
/**
|
|
3004
|
+
* Verify a StoreKit 2 signed transaction and apply its entitlement.
|
|
3005
|
+
* The verified Apple appAccountToken is the only user binding. Do not send a
|
|
3006
|
+
* user id here. Apple requires appAccountToken to be a UUID.
|
|
3007
|
+
*/
|
|
3008
|
+
async syncAppStoreTransaction(signedTransaction) {
|
|
3009
|
+
return agentPost("/_billing/app-store/transactions", { signedTransaction }, "syncAppStoreTransaction");
|
|
3010
|
+
},
|
|
3011
|
+
/**
|
|
3001
3012
|
* Mint a hosted checkout for one of this app's end-users to buy `plan`, in
|
|
3002
3013
|
* the APP OWNER's connected Polar org. Returns the checkout URL to redirect
|
|
3003
3014
|
* to. The amount + product are resolved server-side from the active
|
|
@@ -3213,6 +3224,9 @@ async function createVibesServer(opts) {
|
|
|
3213
3224
|
const url = new URL(req.url);
|
|
3214
3225
|
let filePath = path.join(staticDir, url.pathname);
|
|
3215
3226
|
if (fs.existsSync(filePath) && fs.statSync(filePath).isFile()) return new Response(Bun.file(filePath));
|
|
3227
|
+
const dirIndexPath = path.join(filePath, "index.html");
|
|
3228
|
+
if (fs.existsSync(dirIndexPath) && fs.statSync(dirIndexPath).isFile()) return new Response(Bun.file(dirIndexPath));
|
|
3229
|
+
if (opts.staticFallthrough) return null;
|
|
3216
3230
|
const indexPath = path.join(staticDir, "index.html");
|
|
3217
3231
|
if (fs.existsSync(indexPath)) return new Response(Bun.file(indexPath));
|
|
3218
3232
|
return null;
|
|
@@ -3229,7 +3243,8 @@ async function createVibesServer(opts) {
|
|
|
3229
3243
|
userId: authResult?.userId ?? null,
|
|
3230
3244
|
userEmail: authResult?.userEmail,
|
|
3231
3245
|
userName: authResult?.userName,
|
|
3232
|
-
appId: authResult?.appId
|
|
3246
|
+
appId: authResult?.appId,
|
|
3247
|
+
request: req
|
|
3233
3248
|
}, () => handleRequest(req, routes));
|
|
3234
3249
|
},
|
|
3235
3250
|
async fetch(req) {
|
|
@@ -3252,6 +3267,7 @@ async function createVibesServer(opts) {
|
|
|
3252
3267
|
if (url.pathname.startsWith("/api/")) return instance.apiHandler(req);
|
|
3253
3268
|
const staticResponse = await serveStatic(req);
|
|
3254
3269
|
if (staticResponse) return staticResponse;
|
|
3270
|
+
if (opts.notFound) return opts.notFound(req);
|
|
3255
3271
|
return Response.json({ error: "Not found" }, { status: 404 });
|
|
3256
3272
|
},
|
|
3257
3273
|
migrate(newSchema) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@omg-dev/server",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.42",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -14,9 +14,9 @@
|
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"@restatedev/restate-sdk": "1.14.5",
|
|
17
|
-
"@omg-dev/auth": "0.4.
|
|
18
|
-
"@omg-dev/schema": "0.4.
|
|
19
|
-
"@omg-dev/stream": "0.4.
|
|
17
|
+
"@omg-dev/auth": "0.4.42",
|
|
18
|
+
"@omg-dev/schema": "0.4.42",
|
|
19
|
+
"@omg-dev/stream": "0.4.42",
|
|
20
20
|
"web-push": "^3.6.7"
|
|
21
21
|
},
|
|
22
22
|
"scripts": {
|
package/src/billing.ts
CHANGED
|
@@ -128,6 +128,12 @@ export interface CheckoutOptions {
|
|
|
128
128
|
amountMicros?: number
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
export interface AppStoreTransactionResult {
|
|
132
|
+
plan: string | null
|
|
133
|
+
providerSubscriptionId: string
|
|
134
|
+
duplicate?: boolean
|
|
135
|
+
}
|
|
136
|
+
|
|
131
137
|
export interface GrantOptions {
|
|
132
138
|
idempotencyKey: string
|
|
133
139
|
grantKey?: string
|
|
@@ -265,6 +271,19 @@ export const billing = {
|
|
|
265
271
|
)
|
|
266
272
|
},
|
|
267
273
|
|
|
274
|
+
/**
|
|
275
|
+
* Verify a StoreKit 2 signed transaction and apply its entitlement.
|
|
276
|
+
* The verified Apple appAccountToken is the only user binding. Do not send a
|
|
277
|
+
* user id here. Apple requires appAccountToken to be a UUID.
|
|
278
|
+
*/
|
|
279
|
+
async syncAppStoreTransaction(signedTransaction: string): Promise<AppStoreTransactionResult> {
|
|
280
|
+
return agentPost<AppStoreTransactionResult>(
|
|
281
|
+
"/_billing/app-store/transactions",
|
|
282
|
+
{ signedTransaction },
|
|
283
|
+
"syncAppStoreTransaction",
|
|
284
|
+
)
|
|
285
|
+
},
|
|
286
|
+
|
|
268
287
|
/**
|
|
269
288
|
* Mint a hosted checkout for one of this app's end-users to buy `plan`, in
|
|
270
289
|
* the APP OWNER's connected Polar org. Returns the checkout URL to redirect
|
package/src/ctx.ts
CHANGED
|
@@ -6,6 +6,8 @@ export interface VibesCtx {
|
|
|
6
6
|
userEmail?: string
|
|
7
7
|
userName?: string
|
|
8
8
|
appId?: string
|
|
9
|
+
/** The inbound request for request-scoped server decisions such as GeoIP. */
|
|
10
|
+
request?: Request
|
|
9
11
|
/**
|
|
10
12
|
* True when the current ctx was created by the trigger dispatcher (cron
|
|
11
13
|
* tick or event delivery), not from an inbound HTTP request. Lets handlers
|
|
@@ -30,4 +32,7 @@ export const ctx = {
|
|
|
30
32
|
get appId() {
|
|
31
33
|
return ctxStore.getStore()?.appId
|
|
32
34
|
},
|
|
35
|
+
get request() {
|
|
36
|
+
return ctxStore.getStore()?.request
|
|
37
|
+
},
|
|
33
38
|
}
|
package/src/index.ts
CHANGED
|
@@ -203,6 +203,21 @@ export interface VibesServerOptions {
|
|
|
203
203
|
*/
|
|
204
204
|
workflows?: WorkflowEntry[]
|
|
205
205
|
staticDir?: string
|
|
206
|
+
/**
|
|
207
|
+
* When true, a static miss returns null instead of the index.html SPA shell,
|
|
208
|
+
* letting the caller fall through to its own handler. Set by SSR builds
|
|
209
|
+
* (TanStack Start), where the framework renders every HTML document and an
|
|
210
|
+
* SPA fallback would shadow real routes with a stale shell.
|
|
211
|
+
*/
|
|
212
|
+
staticFallthrough?: boolean
|
|
213
|
+
/**
|
|
214
|
+
* Terminal handler for requests nothing else claimed. Without it `fetch`
|
|
215
|
+
* answers a JSON 404. SSR builds point this at the framework's own fetch
|
|
216
|
+
* handler so page requests get server-rendered — it is the seam that makes
|
|
217
|
+
* "vibes owns /api and assets, the framework owns documents" explicit
|
|
218
|
+
* rather than inferred from a 404 status.
|
|
219
|
+
*/
|
|
220
|
+
notFound?: (req: Request) => Response | Promise<Response>
|
|
206
221
|
schema?: Schema
|
|
207
222
|
/**
|
|
208
223
|
* When false, skip DDL migrations at startup — but still register user-scoped
|
|
@@ -569,6 +584,18 @@ export async function createVibesServer(opts: VibesServerOptions): Promise<Vibes
|
|
|
569
584
|
if (fs.existsSync(filePath) && fs.statSync(filePath).isFile()) {
|
|
570
585
|
return new Response(Bun.file(filePath))
|
|
571
586
|
}
|
|
587
|
+
// Directory index — "/pricing" → "dist/pricing/index.html". This is where
|
|
588
|
+
// the build-time prerender writes per-route static HTML (see prerender.ts),
|
|
589
|
+
// so it MUST be tried before the SPA fallback below: otherwise every route
|
|
590
|
+
// serves the homepage's prerendered markup and the route's own bake is dead
|
|
591
|
+
// weight. Kept ahead of the SSR fallthrough too: a framework that does emit
|
|
592
|
+
// per-route static HTML should have it served rather than re-rendered.
|
|
593
|
+
const dirIndexPath = path.join(filePath, "index.html")
|
|
594
|
+
if (fs.existsSync(dirIndexPath) && fs.statSync(dirIndexPath).isFile()) {
|
|
595
|
+
return new Response(Bun.file(dirIndexPath))
|
|
596
|
+
}
|
|
597
|
+
// SSR owns unmatched paths — see staticFallthrough.
|
|
598
|
+
if (opts.staticFallthrough) return null
|
|
572
599
|
// SPA fallback
|
|
573
600
|
const indexPath = path.join(staticDir, "index.html")
|
|
574
601
|
if (fs.existsSync(indexPath)) {
|
|
@@ -593,6 +620,7 @@ export async function createVibesServer(opts: VibesServerOptions): Promise<Vibes
|
|
|
593
620
|
userEmail: authResult?.userEmail,
|
|
594
621
|
userName: authResult?.userName,
|
|
595
622
|
appId: authResult?.appId,
|
|
623
|
+
request: req,
|
|
596
624
|
},
|
|
597
625
|
() => handleRequest(req, routes),
|
|
598
626
|
)
|
|
@@ -647,6 +675,7 @@ export async function createVibesServer(opts: VibesServerOptions): Promise<Vibes
|
|
|
647
675
|
const staticResponse = await serveStatic(req)
|
|
648
676
|
if (staticResponse) return staticResponse
|
|
649
677
|
|
|
678
|
+
if (opts.notFound) return opts.notFound(req)
|
|
650
679
|
return Response.json({ error: "Not found" }, { status: 404 })
|
|
651
680
|
},
|
|
652
681
|
|