diff --git a/actions/publications/subscribeEmail.tsx b/actions/publications/subscribeEmail.tsx index fe1df0d1..c2dba81e 100644 --- a/actions/publications/subscribeEmail.tsx +++ b/actions/publications/subscribeEmail.tsx @@ -16,7 +16,10 @@ import { getSuppression, deleteSuppression, } from "src/utils/postmarkSuppressions"; -import { unsubscribeToPublication } from "app/lish/subscribeToPublication"; +import { + publishAtprotoSubscriptionForDid, + unsubscribeToPublication, +} from "app/lish/subscribeToPublication"; type RequestError = | "invalid_email" @@ -127,7 +130,15 @@ export async function requestPublicationEmailSubscription( return Err("database_error"); } - if (verifiedIdentity) return Ok({ confirmed: true }); + if (verifiedIdentity) { + if (verifiedIdentity.atp_did) { + await publishAtprotoSubscriptionForDid( + verifiedIdentity.atp_did, + publicationUri, + ); + } + return Ok({ confirmed: true }); + } const sent = await sendConfirmationEmail({ to: email, @@ -191,6 +202,18 @@ export async function confirmPublicationEmailSubscription( return Err("database_error"); } + const { data: confirmedIdentity } = await supabaseServerClient + .from("identities") + .select("atp_did") + .eq("id", identityId) + .maybeSingle(); + if (confirmedIdentity?.atp_did) { + await publishAtprotoSubscriptionForDid( + confirmedIdentity.atp_did, + publicationUri, + ); + } + return Ok(null); } diff --git a/app/api/inngest/client.ts b/app/api/inngest/client.ts index 52f5fbbc..dcd25ce5 100644 --- a/app/api/inngest/client.ts +++ b/app/api/inngest/client.ts @@ -1,112 +1,103 @@ -import { Inngest } from "inngest"; +import { Inngest, eventType, staticSchema } from "inngest"; -import { EventSchemas } from "inngest"; - -export type Events = { - "feeds/index-follows": { - data: { - did: string; - }; - }; - "appview/profile-update": { - data: { - record: any; - did: string; - }; - }; - "appview/index-bsky-post-mention": { - data: { - post_uri: string; - document_link: string; - }; - }; - "appview/come-online": { data: {} }; - "user/migrate-to-standard": { - data: { - did: string; - }; - }; - "user/cleanup-expired-oauth-sessions": { - data: {}; - }; - "user/check-oauth-session": { - data: { +// Event type definitions. In v4, the client no longer has centralized +// schemas — each event is its own EventType, usable both as a trigger and +// as an argument to inngest.send() via event.create(). +export const events = { + feedsIndexFollows: eventType("feeds/index-follows", { + schema: staticSchema<{ did: string }>(), + }), + appviewProfileUpdate: eventType("appview/profile-update", { + schema: staticSchema<{ record: any; did: string }>(), + }), + appviewIndexBskyPostMention: eventType("appview/index-bsky-post-mention", { + schema: staticSchema<{ post_uri: string; document_link: string }>(), + }), + appviewComeOnline: eventType("appview/come-online", { + schema: staticSchema>(), + }), + userMigrateToStandard: eventType("user/migrate-to-standard", { + schema: staticSchema<{ did: string }>(), + }), + userCleanupExpiredOauthSessions: eventType( + "user/cleanup-expired-oauth-sessions", + { schema: staticSchema>() }, + ), + userCheckOauthSession: eventType("user/check-oauth-session", { + schema: staticSchema<{ identityId: string; did: string; tokenCount: number; - }; - }; - "documents/fix-publication-references": { - data: { - documentUris: string[]; - }; - }; - "documents/fix-incorrect-site-values": { - data: { - did: string; - }; - }; - "documents/fix-postref": { - data: { - documentUris?: string[]; - }; - }; - "appview/sync-document-metadata": { - data: { - document_uri: string; - bsky_post_uri?: string; - }; - }; - "user/write-records-to-pds": { - data: { + }>(), + }), + documentsFixPublicationReferences: eventType( + "documents/fix-publication-references", + { schema: staticSchema<{ documentUris: string[] }>() }, + ), + documentsFixIncorrectSiteValues: eventType( + "documents/fix-incorrect-site-values", + { schema: staticSchema<{ did: string }>() }, + ), + documentsFixPostref: eventType("documents/fix-postref", { + schema: staticSchema<{ documentUris?: string[] }>(), + }), + appviewSyncDocumentMetadata: eventType("appview/sync-document-metadata", { + schema: staticSchema<{ document_uri: string; bsky_post_uri?: string }>(), + }), + userWriteRecordsToPds: eventType("user/write-records-to-pds", { + schema: staticSchema<{ did: string; records: Array<{ collection: string; rkey: string; record: unknown; }>; - }; - }; - "stripe/checkout.session.completed": { - data: { - sessionId: string; - }; - }; - "stripe/customer.subscription.updated": { - data: { - subscriptionId: string; - }; - }; - "stripe/customer.subscription.deleted": { - data: { - subscriptionId: string; - }; - }; - "stripe/invoice.payment.succeeded": { - data: { - invoiceId: string; - subscriptionId: string; - customerId: string; - }; - }; - "stripe/invoice.payment.failed": { - data: { + }>(), + }), + stripeCheckoutSessionCompleted: eventType( + "stripe/checkout.session.completed", + { schema: staticSchema<{ sessionId: string }>() }, + ), + stripeCustomerSubscriptionUpdated: eventType( + "stripe/customer.subscription.updated", + { schema: staticSchema<{ subscriptionId: string }>() }, + ), + stripeCustomerSubscriptionDeleted: eventType( + "stripe/customer.subscription.deleted", + { schema: staticSchema<{ subscriptionId: string }>() }, + ), + stripeInvoicePaymentSucceeded: eventType( + "stripe/invoice.payment.succeeded", + { + schema: staticSchema<{ + invoiceId: string; + subscriptionId: string; + customerId: string; + }>(), + }, + ), + stripeInvoicePaymentFailed: eventType("stripe/invoice.payment.failed", { + schema: staticSchema<{ invoiceId: string; subscriptionId: string; customerId: string; - }; - }; - "newsletter/post.send.requested": { - data: { + }>(), + }), + newsletterPostSendRequested: eventType("newsletter/post.send.requested", { + schema: staticSchema<{ publication_uri: string; document_uri: string; root_entity: string; - }; - }; + }>(), + }), }; -// Create a client to send and receive events +// Create a client to send and receive events. +// v4 defaults to cloud mode; opt into dev mode in local development so +// the Inngest dev server can auto-connect without a signing key. export const inngest = new Inngest({ id: "leaflet", - schemas: new EventSchemas().fromRecord(), + isDev: + process.env.INNGEST_DEV === "1" || + process.env.NODE_ENV === "development", }); diff --git a/app/api/inngest/functions/batched_update_profiles.ts b/app/api/inngest/functions/batched_update_profiles.ts index b0b11e30..5bd2013b 100644 --- a/app/api/inngest/functions/batched_update_profiles.ts +++ b/app/api/inngest/functions/batched_update_profiles.ts @@ -1,5 +1,5 @@ import { supabaseServerClient } from "supabase/serverClient"; -import { inngest } from "../client"; +import { inngest, events } from "../client"; export const batched_update_profiles = inngest.createFunction( { @@ -8,8 +8,8 @@ export const batched_update_profiles = inngest.createFunction( maxSize: 100, timeout: "10s", }, + triggers: [events.appviewProfileUpdate], }, - { event: "appview/profile-update" }, async ({ events, step }) => { let existingProfiles = await supabaseServerClient .from("bsky_profiles") diff --git a/app/api/inngest/functions/cleanup_expired_oauth_sessions.ts b/app/api/inngest/functions/cleanup_expired_oauth_sessions.ts index 486cee15..b1d4a7ff 100644 --- a/app/api/inngest/functions/cleanup_expired_oauth_sessions.ts +++ b/app/api/inngest/functions/cleanup_expired_oauth_sessions.ts @@ -1,11 +1,13 @@ import { supabaseServerClient } from "supabase/serverClient"; -import { inngest } from "../client"; +import { inngest, events } from "../client"; import { restoreOAuthSession } from "src/atproto-oauth"; // Main function that fetches identities and publishes events for each one export const cleanup_expired_oauth_sessions = inngest.createFunction( - { id: "cleanup_expired_oauth_sessions" }, - { event: "user/cleanup-expired-oauth-sessions" }, + { + id: "cleanup_expired_oauth_sessions", + triggers: [events.userCleanupExpiredOauthSessions], + }, async ({ step }) => { // Get all identities with an atp_did (OAuth users) that have at least one auth token const identities = await step.run("fetch-oauth-identities", async () => { @@ -70,8 +72,10 @@ export const cleanup_expired_oauth_sessions = inngest.createFunction( // Function that checks a single identity's OAuth session and cleans up if expired export const check_oauth_session = inngest.createFunction( - { id: "check_oauth_session" }, - { event: "user/check-oauth-session" }, + { + id: "check_oauth_session", + triggers: [events.userCheckOauthSession], + }, async ({ event, step }) => { const { identityId, did, tokenCount } = event.data; diff --git a/app/api/inngest/functions/come_online.ts b/app/api/inngest/functions/come_online.ts index e2874691..78fc7a1b 100644 --- a/app/api/inngest/functions/come_online.ts +++ b/app/api/inngest/functions/come_online.ts @@ -1,12 +1,14 @@ import { supabaseServerClient } from "supabase/serverClient"; -import { inngest } from "../client"; +import { inngest, events } from "../client"; import { AtpAgent, AtUri } from "@atproto/api"; import { Json } from "supabase/database.types"; import { ids } from "lexicons/api/lexicons"; export const come_online = inngest.createFunction( - { id: "come_online" }, - { event: "appview/come-online" }, + { + id: "come_online", + triggers: [events.appviewComeOnline], + }, async ({ event, step }) => { return { online: true }; }, diff --git a/app/api/inngest/functions/fix_incorrect_site_values.ts b/app/api/inngest/functions/fix_incorrect_site_values.ts index ac83e091..910e0e14 100644 --- a/app/api/inngest/functions/fix_incorrect_site_values.ts +++ b/app/api/inngest/functions/fix_incorrect_site_values.ts @@ -1,5 +1,5 @@ import { supabaseServerClient } from "supabase/serverClient"; -import { inngest } from "../client"; +import { inngest, events } from "../client"; import { restoreOAuthSession } from "src/atproto-oauth"; import { AtpBaseClient, SiteStandardDocument } from "lexicons/api"; import { AtUri } from "@atproto/syntax"; @@ -52,8 +52,10 @@ function buildValidSiteValues(pubUri: string): Set { * Takes a DID as input and processes publications owned by that identity. */ export const fix_incorrect_site_values = inngest.createFunction( - { id: "fix_incorrect_site_values" }, - { event: "documents/fix-incorrect-site-values" }, + { + id: "fix_incorrect_site_values", + triggers: [events.documentsFixIncorrectSiteValues], + }, async ({ event, step }) => { const { did } = event.data; diff --git a/app/api/inngest/functions/fix_standard_document_postref.ts b/app/api/inngest/functions/fix_standard_document_postref.ts index e38cc798..b83a1701 100644 --- a/app/api/inngest/functions/fix_standard_document_postref.ts +++ b/app/api/inngest/functions/fix_standard_document_postref.ts @@ -1,5 +1,5 @@ import { supabaseServerClient } from "supabase/serverClient"; -import { inngest } from "../client"; +import { inngest, events } from "../client"; import { restoreOAuthSession } from "src/atproto-oauth"; import { AtpBaseClient, @@ -29,8 +29,10 @@ async function createAuthenticatedAgent(did: string): Promise { * if no URIs are provided. */ export const fix_standard_document_postref = inngest.createFunction( - { id: "fix_standard_document_postref" }, - { event: "documents/fix-postref" }, + { + id: "fix_standard_document_postref", + triggers: [events.documentsFixPostref], + }, async ({ event, step }) => { const { documentUris: providedUris } = event.data as { documentUris?: string[]; diff --git a/app/api/inngest/functions/fix_standard_document_publications.ts b/app/api/inngest/functions/fix_standard_document_publications.ts index 8b1657e3..90b4b092 100644 --- a/app/api/inngest/functions/fix_standard_document_publications.ts +++ b/app/api/inngest/functions/fix_standard_document_publications.ts @@ -1,5 +1,5 @@ import { supabaseServerClient } from "supabase/serverClient"; -import { inngest } from "../client"; +import { inngest, events } from "../client"; import { restoreOAuthSession } from "src/atproto-oauth"; import { AtpBaseClient, SiteStandardDocument } from "lexicons/api"; import { AtUri } from "@atproto/syntax"; @@ -21,8 +21,10 @@ async function createAuthenticatedAgent(did: string): Promise { * references in their site field. Updates both the PDS record and database. */ export const fix_standard_document_publications = inngest.createFunction( - { id: "fix_standard_document_publications" }, - { event: "documents/fix-publication-references" }, + { + id: "fix_standard_document_publications", + triggers: [events.documentsFixPublicationReferences], + }, async ({ event, step }) => { const { documentUris } = event.data as { documentUris: string[] }; diff --git a/app/api/inngest/functions/index_follows.ts b/app/api/inngest/functions/index_follows.ts index 310f42eb..2399ff82 100644 --- a/app/api/inngest/functions/index_follows.ts +++ b/app/api/inngest/functions/index_follows.ts @@ -1,6 +1,6 @@ import { supabaseServerClient } from "supabase/serverClient"; import { AtpAgent, AtUri } from "@atproto/api"; -import { inngest } from "../client"; +import { inngest, events } from "../client"; export const index_follows = inngest.createFunction( { @@ -10,8 +10,8 @@ export const index_follows = inngest.createFunction( period: "5m", key: "event.data.did", }, + triggers: [events.feedsIndexFollows], }, - { event: "feeds/index-follows" }, async ({ event, step }) => { let follows: string[] = []; let cursor: null | string = null; diff --git a/app/api/inngest/functions/index_post_mention.ts b/app/api/inngest/functions/index_post_mention.ts index 80ff24f9..0763fd9c 100644 --- a/app/api/inngest/functions/index_post_mention.ts +++ b/app/api/inngest/functions/index_post_mention.ts @@ -1,5 +1,5 @@ import { supabaseServerClient } from "supabase/serverClient"; -import { inngest } from "../client"; +import { inngest, events } from "../client"; import { AtpAgent, AtUri } from "@atproto/api"; import { Json } from "supabase/database.types"; import { ids } from "lexicons/api/lexicons"; @@ -12,8 +12,10 @@ import { idResolver } from "app/(home-pages)/reader/idResolver"; import { documentUriFilter } from "src/utils/uriHelpers"; export const index_post_mention = inngest.createFunction( - { id: "index_post_mention" }, - { event: "appview/index-bsky-post-mention" }, + { + id: "index_post_mention", + triggers: [events.appviewIndexBskyPostMention], + }, async ({ event, step }) => { let url = new URL(event.data.document_link); let path = url.pathname.split("/").filter(Boolean); diff --git a/app/api/inngest/functions/migrate_user_to_standard.ts b/app/api/inngest/functions/migrate_user_to_standard.ts index ef5abe0b..bfafb41c 100644 --- a/app/api/inngest/functions/migrate_user_to_standard.ts +++ b/app/api/inngest/functions/migrate_user_to_standard.ts @@ -1,5 +1,5 @@ import { supabaseServerClient } from "supabase/serverClient"; -import { inngest } from "../client"; +import { inngest, events } from "../client"; import { restoreOAuthSession } from "src/atproto-oauth"; import { AtpBaseClient, @@ -30,8 +30,10 @@ async function createAuthenticatedAgent(did: string): Promise { } export const migrate_user_to_standard = inngest.createFunction( - { id: "migrate_user_to_standard" }, - { event: "user/migrate-to-standard" }, + { + id: "migrate_user_to_standard", + triggers: [events.userMigrateToStandard], + }, async ({ event, step }) => { const { did } = event.data; diff --git a/app/api/inngest/functions/send_post_broadcast.ts b/app/api/inngest/functions/send_post_broadcast.ts index 31286d0b..b17bb646 100644 --- a/app/api/inngest/functions/send_post_broadcast.ts +++ b/app/api/inngest/functions/send_post_broadcast.ts @@ -1,6 +1,6 @@ import { render } from "@react-email/render"; import { AtUri } from "@atproto/syntax"; -import { inngest } from "../client"; +import { inngest, events } from "../client"; import { supabaseServerClient } from "supabase/serverClient"; import { PostEmail } from "emails/post"; import { emailPropsFromPublication } from "emails/fromPublication"; @@ -35,8 +35,8 @@ export const send_post_broadcast = inngest.createFunction( .eq("publication", publication_uri) .eq("document", document_uri); }, + triggers: [events.newsletterPostSendRequested], }, - { event: "newsletter/post.send.requested" }, async ({ event, step }) => { const { publication_uri, document_uri } = event.data; diff --git a/app/api/inngest/functions/sync_document_metadata.ts b/app/api/inngest/functions/sync_document_metadata.ts index c5609304..41faf3f2 100644 --- a/app/api/inngest/functions/sync_document_metadata.ts +++ b/app/api/inngest/functions/sync_document_metadata.ts @@ -1,4 +1,4 @@ -import { inngest } from "../client"; +import { inngest, events } from "../client"; import { supabaseServerClient } from "supabase/serverClient"; import { AtpAgent, AtUri } from "@atproto/api"; import { idResolver } from "app/(home-pages)/reader/idResolver"; @@ -17,8 +17,8 @@ export const sync_document_metadata = inngest.createFunction( timeout: "3m", }, concurrency: [{ key: "event.data.document_uri", limit: 1 }], + triggers: [events.appviewSyncDocumentMetadata], }, - { event: "appview/sync-document-metadata" }, async ({ event, step }) => { const { document_uri, bsky_post_uri } = event.data; diff --git a/app/api/inngest/functions/write_records_to_pds.ts b/app/api/inngest/functions/write_records_to_pds.ts index c03b67f7..2d296ac8 100644 --- a/app/api/inngest/functions/write_records_to_pds.ts +++ b/app/api/inngest/functions/write_records_to_pds.ts @@ -1,4 +1,4 @@ -import { inngest } from "../client"; +import { inngest, events } from "../client"; import { restoreOAuthSession } from "src/atproto-oauth"; import { AtpBaseClient } from "lexicons/api"; @@ -16,8 +16,10 @@ async function createAuthenticatedAgent(did: string): Promise { } export const write_records_to_pds = inngest.createFunction( - { id: "write-records-to-pds" }, - { event: "user/write-records-to-pds" }, + { + id: "write-records-to-pds", + triggers: [events.userWriteRecordsToPds], + }, async ({ event, step }) => { const { did, records } = event.data; diff --git a/app/lish/subscribeToPublication.ts b/app/lish/subscribeToPublication.ts index b1d0c2af..db64f7af 100644 --- a/app/lish/subscribeToPublication.ts +++ b/app/lish/subscribeToPublication.ts @@ -111,6 +111,87 @@ export async function subscribeToPublication( }; } +// Best-effort publish of an AT Protocol subscription record for a known DID. +// Used by the email-subscribe flow when the subscribing email is linked to an +// atp_did: we want the user's PDS record to match their email subscription. +// Swallows all failures — the email subscription is the source of truth and +// must succeed regardless of whether the atproto write goes through. +export async function publishAtprotoSubscriptionForDid( + atp_did: string, + publication: string, +): Promise { + try { + let { data: existingSubscription } = await supabaseServerClient + .from("publication_subscriptions") + .select("uri") + .eq("identity", atp_did) + .eq("publication", publication) + .maybeSingle(); + if (existingSubscription) return; + + const sessionResult = await restoreOAuthSession(atp_did); + if (!sessionResult.ok) return; + let credentialSession = sessionResult.value; + let agent = new AtpBaseClient( + credentialSession.fetchHandler.bind(credentialSession), + ); + + let record = await agent.site.standard.graph.subscription.create( + { repo: atp_did, rkey: TID.nextStr() }, + { publication }, + ); + await supabaseServerClient.from("publication_subscriptions").insert({ + uri: record.uri, + record, + publication, + identity: atp_did, + }); + + let publicationOwner = new AtUri(publication).host; + if (publicationOwner !== atp_did) { + let notification: Notification = { + id: v7(), + recipient: publicationOwner, + data: { + type: "subscribe", + subscription_uri: record.uri, + }, + }; + await supabaseServerClient.from("notifications").insert(notification); + await pingIdentityToUpdateNotification(publicationOwner); + } + + let { data: existingProfile } = await supabaseServerClient + .from("bsky_profiles") + .select("did") + .eq("did", atp_did) + .maybeSingle(); + if (!existingProfile) { + let bsky = new BskyAgent(credentialSession); + let [profile, resolveDid] = await Promise.all([ + bsky.app.bsky.actor.profile + .get({ repo: atp_did, rkey: "self" }) + .catch(() => null), + idResolver.did.resolve(atp_did).catch(() => null), + ]); + if (profile?.value) { + await supabaseServerClient.from("bsky_profiles").insert({ + did: atp_did, + record: profile.value as Json, + handle: resolveDid?.alsoKnownAs?.[0]?.slice(5), + }); + } + } + } catch (e) { + console.error( + "[publishAtprotoSubscriptionForDid] failed:", + atp_did, + publication, + e, + ); + } +} + type UnsubscribeResult = | { success: true } | { success: false; error: OAuthSessionError }; diff --git a/package-lock.json b/package-lock.json index b9ac2691..21b5c956 100644 --- a/package-lock.json +++ b/package-lock.json @@ -52,7 +52,7 @@ "hls.js": "^1.6.15", "hono": "^4.7.11", "immer": "^10.2.0", - "inngest": "^3.52.6", + "inngest": "^4.2.4", "ioredis": "^5.6.1", "katex": "^0.16.22", "l": "^0.6.0", @@ -11306,6 +11306,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -14599,6 +14600,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "devOptional": true, "engines": { "node": ">=8" } @@ -15187,9 +15189,9 @@ "license": "MIT" }, "node_modules/inngest": { - "version": "3.52.6", - "resolved": "https://registry.npmjs.org/inngest/-/inngest-3.52.6.tgz", - "integrity": "sha512-wDxA1I5CIL7anqyX3Vr0T/5kOHkWN8W5oeqbHhFKFbsFrM+M/J3OEFiRRgcdiGyhNHxPvWaRdQb4N2mfgwc7PQ==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/inngest/-/inngest-4.2.4.tgz", + "integrity": "sha512-MBFcRhhQ+dcGHLYCbIcMYxiAZCxzfAx0+3b/euYQKc7MK3rOnNHaNHuF2e0WsT13oWJiGzjuC3T4Nocggmh5WQ==", "license": "Apache-2.0", "dependencies": { "@bufbuild/protobuf": "^2.2.3", @@ -15207,14 +15209,12 @@ "@types/debug": "^4.1.12", "@types/ms": "~2.1.0", "canonicalize": "^1.0.8", - "chalk": "^4.1.2", "cross-fetch": "^4.0.0", "debug": "^4.3.4", "hash.js": "^1.1.7", "json-stringify-safe": "^5.0.1", "ms": "^2.1.3", "serialize-error-cjs": "^0.1.3", - "strip-ansi": "^5.2.0", "temporal-polyfill": "^0.2.5", "ulid": "^2.3.0", "zod": "^3.25.0" @@ -15232,6 +15232,7 @@ "hono": ">=4.2.7", "koa": ">=2.14.2", "next": ">=12.0.0", + "react": ">=18.0.0", "typescript": ">=5.8.0", "zod": "^3.25.0 || ^4.0.0" }, @@ -15263,32 +15264,14 @@ "next": { "optional": true }, + "react": { + "optional": true + }, "typescript": { "optional": true } } }, - "node_modules/inngest/node_modules/ansi-regex": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", - "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/inngest/node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/internal-slot": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", @@ -22292,6 +22275,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, "dependencies": { "has-flag": "^4.0.0" }, diff --git a/package.json b/package.json index 8e3d977f..26c268e2 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "hls.js": "^1.6.15", "hono": "^4.7.11", "immer": "^10.2.0", - "inngest": "^3.52.6", + "inngest": "^4.2.4", "ioredis": "^5.6.1", "katex": "^0.16.22", "l": "^0.6.0", diff --git a/tsconfig.json b/tsconfig.json index 43324c37..471184e7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -18,7 +18,7 @@ "module": "esnext", "downlevelIteration": true, "esModuleInterop": true, - "moduleResolution": "node", + "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, "jsx": "react-jsx",