@frigear-nu/stripe 0.1.2 → 0.1.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/dist/module.json +1 -1
- package/dist/module.mjs +5 -8
- package/dist/runtime/server/routes/webhook.post.js +6 -5
- package/dist/runtime/server/utils/stripe.js +3 -2
- package/dist/runtime/utils/index.d.ts +0 -1
- package/dist/runtime/utils/index.js +0 -1
- package/package.json +3 -3
- package/dist/runtime/utils/url.d.ts +0 -6
- package/dist/runtime/utils/url.js +0 -11
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { defineNuxtModule, createResolver,
|
|
2
|
-
import { registerModule, inlineModuleRuntime, defineVirtualRegistry, extendDatabaseTable } from '@frigear-nu/module-kit/utils';
|
|
1
|
+
import { defineNuxtModule, createResolver, addServerImportsDir, addServerImports, addTypeTemplate } from '@nuxt/kit';
|
|
2
|
+
import { registerModule, addModuleRoutes, inlineModuleRuntime, defineVirtualRegistry, extendDatabaseTable } from '@frigear-nu/module-kit/utils';
|
|
3
3
|
|
|
4
4
|
const STRIPE_API_VERSION = "2026-09-30.endive";
|
|
5
5
|
const DEFAULT_WEBHOOK_PATH = "/api/stripe/webhook";
|
|
@@ -25,7 +25,8 @@ const module$1 = defineNuxtModule({
|
|
|
25
25
|
async setup(options, nuxt) {
|
|
26
26
|
registerModule("@frigear-nu/stripe", nuxt);
|
|
27
27
|
const resolver = createResolver(import.meta.url);
|
|
28
|
-
const
|
|
28
|
+
const configuredPath = options.settings?.webhookPath || DEFAULT_WEBHOOK_PATH;
|
|
29
|
+
const webhookPath = configuredPath.startsWith("/") ? configuredPath : `/${configuredPath}`;
|
|
29
30
|
if (!nuxt.options.hub?.kv) {
|
|
30
31
|
throw new Error("[@frigear-nu/stripe] NuxtHub KV is required for webhook idempotency. Set `hub: { kv: true }` in your Nuxt config.");
|
|
31
32
|
}
|
|
@@ -40,11 +41,7 @@ const module$1 = defineNuxtModule({
|
|
|
40
41
|
publishableKey: "",
|
|
41
42
|
...runtimeConfig.public.stripe
|
|
42
43
|
};
|
|
43
|
-
|
|
44
|
-
route: webhookPath,
|
|
45
|
-
method: "post",
|
|
46
|
-
handler: resolver.resolve("./runtime/server/routes/webhook.post")
|
|
47
|
-
});
|
|
44
|
+
addModuleRoutes(resolver, [{ method: "post", path: webhookPath, file: "webhook.post" }], { base: "/api/stripe" });
|
|
48
45
|
addServerImportsDir(resolver.resolve("./runtime/server/utils"));
|
|
49
46
|
inlineModuleRuntime(nuxt, resolver);
|
|
50
47
|
addServerImports([
|
|
@@ -2,6 +2,7 @@ import Stripe from "stripe";
|
|
|
2
2
|
import { kv } from "@nuxthub/kv";
|
|
3
3
|
import { handlers as registeredHandlers } from "#stripe/handlers";
|
|
4
4
|
import { getRuntimeStripeEventHandlers } from "../../utils/registry.js";
|
|
5
|
+
import { apiError, badRequest, notConfigured } from "@frigear-nu/module-kit/server";
|
|
5
6
|
const PROCESSED_TTL_SECONDS = 60 * 60 * 24 * 7;
|
|
6
7
|
const DEFAULT_ORDER = 100;
|
|
7
8
|
const matches = (events, type) => events === "*" || events.includes(type);
|
|
@@ -26,15 +27,15 @@ function getEventCustomerId(stripeEvent) {
|
|
|
26
27
|
export default defineEventHandler(async (event) => {
|
|
27
28
|
const { webhookSecret } = useRuntimeConfig(event).stripe;
|
|
28
29
|
if (!webhookSecret) {
|
|
29
|
-
throw
|
|
30
|
+
throw notConfigured("Stripe webhook is not configured (missing NUXT_STRIPE_WEBHOOK_SECRET).");
|
|
30
31
|
}
|
|
31
32
|
const signature = getHeader(event, "stripe-signature");
|
|
32
33
|
if (!signature) {
|
|
33
|
-
throw
|
|
34
|
+
throw badRequest("Missing stripe-signature header.");
|
|
34
35
|
}
|
|
35
36
|
const rawBody = await readRawBody(event, "utf8");
|
|
36
37
|
if (!rawBody) {
|
|
37
|
-
throw
|
|
38
|
+
throw badRequest("Missing request body.");
|
|
38
39
|
}
|
|
39
40
|
let stripeEvent;
|
|
40
41
|
try {
|
|
@@ -47,7 +48,7 @@ export default defineEventHandler(async (event) => {
|
|
|
47
48
|
);
|
|
48
49
|
} catch (error) {
|
|
49
50
|
console.warn("[@frigear-nu/stripe] Rejected webhook with an invalid signature:", error instanceof Error ? error.message : error);
|
|
50
|
-
throw
|
|
51
|
+
throw badRequest("Invalid Stripe signature.");
|
|
51
52
|
}
|
|
52
53
|
const processedKey = `stripe:event:${stripeEvent.id}`;
|
|
53
54
|
if (await kv.has(processedKey)) {
|
|
@@ -75,7 +76,7 @@ export default defineEventHandler(async (event) => {
|
|
|
75
76
|
console.error(`[@frigear-nu/stripe] "stripe:event" hook failed for ${stripeEvent.id}:`, error);
|
|
76
77
|
}
|
|
77
78
|
if (failures > 0) {
|
|
78
|
-
throw
|
|
79
|
+
throw apiError(500, "handler_failed", `${failures} Stripe event handler(s) failed.`);
|
|
79
80
|
}
|
|
80
81
|
await kv.set(processedKey, Date.now(), { ttl: PROCESSED_TTL_SECONDS });
|
|
81
82
|
return { received: true };
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import Stripe from "stripe";
|
|
2
2
|
import { db, schema } from "@nuxthub/db";
|
|
3
3
|
import { and, eq, isNull } from "drizzle-orm";
|
|
4
|
+
import { notConfigured, notFound } from "@frigear-nu/module-kit/server";
|
|
4
5
|
let cached;
|
|
5
6
|
export function useStripe() {
|
|
6
7
|
const { secretKey, apiVersion } = useRuntimeConfig().stripe;
|
|
7
8
|
if (!secretKey) {
|
|
8
|
-
throw
|
|
9
|
+
throw notConfigured("Stripe is not configured (missing `runtimeConfig.stripe.secretKey` / NUXT_STRIPE_SECRET_KEY).");
|
|
9
10
|
}
|
|
10
11
|
if (!cached || cached.key !== secretKey || cached.apiVersion !== apiVersion) {
|
|
11
12
|
cached = {
|
|
@@ -23,7 +24,7 @@ const escapeSearchValue = (value) => value.replace(/\\/g, "\\\\").replace(/'/g,
|
|
|
23
24
|
export async function ensureStripeCustomer(userId) {
|
|
24
25
|
const [user] = await db.select().from(schema.users).where(eq(schema.users.id, userId)).limit(1);
|
|
25
26
|
if (!user) {
|
|
26
|
-
throw
|
|
27
|
+
throw notFound("User not found.");
|
|
27
28
|
}
|
|
28
29
|
if (user.stripeCustomerId) return user.stripeCustomerId;
|
|
29
30
|
const stripe = useStripe();
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
export { registerStripeEventHandler, defineStripeEventHandler } from './handlers.js';
|
|
2
2
|
export type { RegisterStripeEventHandlerOptions } from './handlers.js';
|
|
3
3
|
export { onStripeEvent } from './registry.js';
|
|
4
|
-
export { resolveSameOriginUrl } from './url.js';
|
|
5
4
|
export type { ModuleOptions, StripeEventType, StripeEventOf, StripeEventHandler, StripeEventHandlerContext, RegisteredStripeEventHandler, StripeRuntimeConfig, StripePublicRuntimeConfig, } from '../../types.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frigear-nu/stripe",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Core Stripe plumbing for the frigear ecosystem: SDK access, customer linking, and a verified, idempotent webhook that other modules can subscribe to.",
|
|
5
5
|
"homepage": "https://docs.frigear.dev/modules/stripe",
|
|
6
6
|
"repository": {
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
"playground"
|
|
31
31
|
],
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@frigear-nu/module-kit": "1.1.
|
|
34
|
-
"@frigear-nu/users": "1.1.
|
|
33
|
+
"@frigear-nu/module-kit": "1.1.3",
|
|
34
|
+
"@frigear-nu/users": "1.1.4",
|
|
35
35
|
"@libsql/client": "^0.18.0",
|
|
36
36
|
"@nuxt/kit": "^4.6.1",
|
|
37
37
|
"h3": "^1.15.11",
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Validates a redirect URL supplied by a client (a Stripe return URL): it must be a relative path (`/x`) or an absolute
|
|
3
|
-
* URL on `origin`. Returns an absolute URL on that origin, or `null` when it is unsafe. Shared by every module that
|
|
4
|
-
* sends people through Stripe so the open-redirect guard exists once.
|
|
5
|
-
*/
|
|
6
|
-
export declare function resolveSameOriginUrl(input: string, origin: string): string | null;
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export function resolveSameOriginUrl(input, origin) {
|
|
2
|
-
if (input.startsWith("/")) {
|
|
3
|
-
if (input.startsWith("//") || input.startsWith("/\\")) return null;
|
|
4
|
-
return `${origin}${input}`;
|
|
5
|
-
}
|
|
6
|
-
try {
|
|
7
|
-
return new URL(input).origin === new URL(origin).origin ? input : null;
|
|
8
|
-
} catch {
|
|
9
|
-
return null;
|
|
10
|
-
}
|
|
11
|
-
}
|