@simpleapps-com/augur-server 0.2.0 → 0.2.1

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/auth.js CHANGED
@@ -1,5 +1,3 @@
1
- import "./chunk-DGUM43GV.js";
2
-
3
1
  // src/auth.ts
4
2
  import Credentials from "next-auth/providers/credentials";
5
3
  function buildInternalCallbacks(augurClient) {
package/dist/auth.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/auth.ts"],"sourcesContent":["// @simpleapps-com/augur-server/auth\n// NextAuth 5 configuration factory for Augur ecommerce sites.\n\nimport type { NextAuthConfig } from \"next-auth\";\nimport Credentials from \"next-auth/providers/credentials\";\n\n/** Base user fields shared across all Augur sites. */\nexport interface AugurUser {\n id: string;\n username: string;\n isVerified: boolean;\n name?: string;\n email?: string;\n customerId?: string | number;\n contactId?: string | number;\n cartHdrUid?: number;\n token?: string;\n}\n\n/** Session shape returned by all Augur sites. */\nexport interface AugurSession {\n user: AugurUser;\n token?: string;\n expires: string;\n}\n\n/** JWT token shape used by Augur auth. */\nexport interface AugurJWT {\n id: string;\n username: string;\n isVerified: boolean;\n token?: string;\n}\n\n/** Site-specific callbacks the consumer can provide. */\nexport interface AugurAuthCallbacks {\n /** Fetch user profile from the Augur API given the user's Joomla ID. */\n getUserProfile: (userId: string) => Promise<AugurUser | null>;\n /** Look up or create a cart header for the authenticated user. */\n cartHdrLookup?: (\n userId: string | number,\n token: string,\n contactId: string | number,\n customerId: string | number,\n ) => Promise<{ cartHdrUid?: number } | null>;\n}\n\n/**\n * Minimal interface for the Augur SDK client used by auth internals.\n * Any `AugurAPI` instance from `@simpleapps-com/augur-api` satisfies this.\n */\nexport interface AugurAuthClient {\n joomla: {\n users: {\n doc: {\n get(\n userId: number,\n params?: { edgeCache?: number | string },\n ): Promise<{\n data: {\n id: number;\n name: string;\n username: string;\n email: string;\n customerId?: string;\n contactId?: string;\n };\n }>;\n };\n };\n };\n commerce: {\n cartHdr: {\n lookup: {\n get(params: {\n userId: number;\n customerId: number;\n contactId: number;\n cartToken?: string;\n }): Promise<{\n data: { cartHdrUid?: number };\n }>;\n };\n };\n };\n}\n\nexport interface CreateAuthConfigOptions {\n /** Augur SDK client. When provided, auth SDK calls are handled internally. */\n augurClient?: AugurAuthClient;\n /** Site-specific callbacks. Override internal SDK calls when custom behavior is needed. */\n callbacks?: Partial<AugurAuthCallbacks>;\n /** NextAuth secret (defaults to NEXT_PUBLIC_AUTH_SECRET env var). */\n secret?: string;\n /** Session max age in seconds (defaults to 4 hours). */\n maxAge?: number;\n /** Default customer ID when profile doesn't provide one. */\n defaultCustomerId?: string | number;\n /** Default contact ID for cart header lookups. */\n defaultContactId?: string | number;\n /** Enable NextAuth debug logging (defaults to NODE_ENV === \"development\"). */\n debug?: boolean;\n}\n\n/** Build internal callbacks that call the Augur SDK directly. */\nfunction buildInternalCallbacks(\n augurClient: AugurAuthClient,\n): AugurAuthCallbacks {\n return {\n async getUserProfile(userId: string): Promise<AugurUser | null> {\n if (!userId) return null;\n const uid = parseInt(userId, 10);\n if (isNaN(uid)) return null;\n const result = await augurClient.joomla.users.doc.get(uid, {\n edgeCache: 1,\n });\n const data = result.data;\n if (!data) return null;\n return {\n id: String(data.id),\n name: data.name,\n username: data.username,\n email: data.email,\n isVerified: true,\n customerId: data.customerId,\n contactId: data.contactId,\n };\n },\n async cartHdrLookup(\n userId: string | number,\n _token: string,\n contactId: string | number,\n customerId: string | number,\n ): Promise<{ cartHdrUid?: number } | null> {\n const result = await augurClient.commerce.cartHdr.lookup.get({\n userId: Number(userId) || 0,\n customerId: Number(customerId) || 0,\n contactId: Number(contactId) || 0,\n });\n return result.data ?? null;\n },\n };\n}\n\n/** Resolve final callbacks: callback overrides take priority over internal SDK calls. */\nfunction resolveCallbacks(\n options: CreateAuthConfigOptions,\n): AugurAuthCallbacks {\n const { augurClient, callbacks } = options;\n\n if (augurClient) {\n const internal = buildInternalCallbacks(augurClient);\n return {\n getUserProfile: callbacks?.getUserProfile ?? internal.getUserProfile,\n cartHdrLookup: callbacks?.cartHdrLookup ?? internal.cartHdrLookup,\n };\n }\n\n if (!callbacks?.getUserProfile) {\n throw new Error(\n \"createAuthConfig requires either `augurClient` or `callbacks.getUserProfile`\",\n );\n }\n\n return {\n getUserProfile: callbacks.getUserProfile,\n cartHdrLookup: callbacks.cartHdrLookup,\n };\n}\n\n/**\n * Create a NextAuth 5 configuration for an Augur ecommerce site.\n *\n * Accepts either an `augurClient` (recommended) for zero-boilerplate auth,\n * or explicit `callbacks` for custom behavior. Callback overrides take\n * priority when both are provided.\n *\n * @example\n * ```ts\n * // Recommended: pass the SDK client directly\n * import NextAuth from \"next-auth\";\n * import { createAuthConfig } from \"@simpleapps-com/augur-server/auth\";\n * import { augurClient } from \"@/lib/augur-client\";\n *\n * export const { handlers, signIn, signOut, auth } = NextAuth(\n * createAuthConfig({\n * augurClient,\n * defaultCustomerId: process.env.NEXT_PUBLIC_DEFAULT_CUSTOMER_ID,\n * defaultContactId: process.env.NEXT_PUBLIC_DEFAULT_CONTACT_ID,\n * }),\n * );\n * ```\n *\n * @example\n * ```ts\n * // Custom callbacks (backward-compatible)\n * import NextAuth from \"next-auth\";\n * import { createAuthConfig } from \"@simpleapps-com/augur-server/auth\";\n *\n * export const { handlers, signIn, signOut, auth } = NextAuth(\n * createAuthConfig({\n * callbacks: { getUserProfile, cartHdrLookup },\n * defaultCustomerId: process.env.NEXT_PUBLIC_DEFAULT_CUSTOMER_ID,\n * }),\n * );\n * ```\n */\nasync function lookupCartHdr(\n siteCallbacks: AugurAuthCallbacks,\n profile: AugurUser,\n defaultCustomerId?: string | number,\n defaultContactId?: string | number,\n): Promise<number | undefined> {\n if (!siteCallbacks.cartHdrLookup || !profile.id) return undefined;\n const cartHdr = await siteCallbacks.cartHdrLookup(\n profile.id,\n \"\",\n profile.contactId ?? defaultContactId ?? \"\",\n profile.customerId ?? defaultCustomerId ?? \"\",\n );\n return cartHdr?.cartHdrUid;\n}\n\nexport function createAuthConfig(\n options: CreateAuthConfigOptions,\n): NextAuthConfig {\n const {\n secret = process.env.NEXT_PUBLIC_AUTH_SECRET,\n maxAge = 4 * 60 * 60,\n defaultCustomerId,\n defaultContactId,\n debug = process.env.NODE_ENV === \"development\",\n } = options;\n\n const siteCallbacks = resolveCallbacks(options);\n\n return {\n providers: [\n Credentials({\n name: \"Credentials\",\n credentials: {\n username: { label: \"Username\", type: \"text\" },\n password: { label: \"Password\", type: \"password\" },\n id: { label: \"ID\", type: \"text\" },\n isVerified: { label: \"Is Verified\", type: \"text\" },\n token: { label: \"Token\", type: \"text\" },\n },\n async authorize(credentials) {\n if (!credentials) return null;\n\n const { id, isVerified, username, token } = credentials as {\n id: string;\n isVerified: string;\n username: string;\n token: string;\n };\n\n return {\n id,\n isVerified: isVerified === \"true\",\n username,\n token,\n };\n },\n }),\n ],\n callbacks: {\n async signIn() {\n return true;\n },\n async redirect({ baseUrl }) {\n return baseUrl;\n },\n async session({ session, token }) {\n const baseUser = {\n id: (token.id as string) || \"\",\n username: (token.username as string) || \"\",\n isVerified: (token.isVerified as boolean) || false,\n };\n\n const buildSession = (userOverrides = {}) => ({\n ...session,\n user: { ...session.user, ...baseUser, ...userOverrides },\n token: token.token as string | undefined,\n });\n\n try {\n const userProfile = await siteCallbacks.getUserProfile(baseUser.id);\n if (!userProfile) return buildSession();\n\n const cartHdrUid = await lookupCartHdr(\n siteCallbacks,\n userProfile,\n defaultCustomerId,\n defaultContactId,\n );\n\n return buildSession({\n name: userProfile.name ?? session.user?.name,\n email: userProfile.email ?? session.user?.email,\n customerId: userProfile.customerId ?? defaultCustomerId,\n contactId: userProfile.contactId,\n cartHdrUid,\n });\n } catch {\n return buildSession();\n }\n },\n async jwt({ token, user }) {\n if (user) {\n const typedUser = user as {\n id: string;\n isVerified: boolean;\n username: string;\n token: string;\n };\n\n return {\n ...token,\n id: typedUser.id,\n isVerified: typedUser.isVerified,\n username: typedUser.username,\n token: typedUser.token,\n };\n }\n return token;\n },\n },\n secret,\n debug,\n session: {\n strategy: \"jwt\",\n maxAge,\n },\n trustHost: true,\n };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/auth.ts"],"sourcesContent":["// @simpleapps-com/augur-server/auth\n// NextAuth 5 configuration factory for Augur ecommerce sites.\n\nimport type { NextAuthConfig } from \"next-auth\";\nimport Credentials from \"next-auth/providers/credentials\";\n\n/** Base user fields shared across all Augur sites. */\nexport interface AugurUser {\n id: string;\n username: string;\n isVerified: boolean;\n name?: string;\n email?: string;\n customerId?: string | number;\n contactId?: string | number;\n cartHdrUid?: number;\n token?: string;\n}\n\n/** Session shape returned by all Augur sites. */\nexport interface AugurSession {\n user: AugurUser;\n token?: string;\n expires: string;\n}\n\n/** JWT token shape used by Augur auth. */\nexport interface AugurJWT {\n id: string;\n username: string;\n isVerified: boolean;\n token?: string;\n}\n\n/** Site-specific callbacks the consumer can provide. */\nexport interface AugurAuthCallbacks {\n /** Fetch user profile from the Augur API given the user's Joomla ID. */\n getUserProfile: (userId: string) => Promise<AugurUser | null>;\n /** Look up or create a cart header for the authenticated user. */\n cartHdrLookup?: (\n userId: string | number,\n token: string,\n contactId: string | number,\n customerId: string | number,\n ) => Promise<{ cartHdrUid?: number } | null>;\n}\n\n/**\n * Minimal interface for the Augur SDK client used by auth internals.\n * Any `AugurAPI` instance from `@simpleapps-com/augur-api` satisfies this.\n */\nexport interface AugurAuthClient {\n joomla: {\n users: {\n doc: {\n get(\n userId: number,\n params?: { edgeCache?: number | string },\n ): Promise<{\n data: {\n id: number;\n name: string;\n username: string;\n email: string;\n customerId?: string;\n contactId?: string;\n };\n }>;\n };\n };\n };\n commerce: {\n cartHdr: {\n lookup: {\n get(params: {\n userId: number;\n customerId: number;\n contactId: number;\n cartToken?: string;\n }): Promise<{\n data: { cartHdrUid?: number };\n }>;\n };\n };\n };\n}\n\nexport interface CreateAuthConfigOptions {\n /** Augur SDK client. When provided, auth SDK calls are handled internally. */\n augurClient?: AugurAuthClient;\n /** Site-specific callbacks. Override internal SDK calls when custom behavior is needed. */\n callbacks?: Partial<AugurAuthCallbacks>;\n /** NextAuth secret (defaults to NEXT_PUBLIC_AUTH_SECRET env var). */\n secret?: string;\n /** Session max age in seconds (defaults to 4 hours). */\n maxAge?: number;\n /** Default customer ID when profile doesn't provide one. */\n defaultCustomerId?: string | number;\n /** Default contact ID for cart header lookups. */\n defaultContactId?: string | number;\n /** Enable NextAuth debug logging (defaults to NODE_ENV === \"development\"). */\n debug?: boolean;\n}\n\n/** Build internal callbacks that call the Augur SDK directly. */\nfunction buildInternalCallbacks(\n augurClient: AugurAuthClient,\n): AugurAuthCallbacks {\n return {\n async getUserProfile(userId: string): Promise<AugurUser | null> {\n if (!userId) return null;\n const uid = parseInt(userId, 10);\n if (isNaN(uid)) return null;\n const result = await augurClient.joomla.users.doc.get(uid, {\n edgeCache: 1,\n });\n const data = result.data;\n if (!data) return null;\n return {\n id: String(data.id),\n name: data.name,\n username: data.username,\n email: data.email,\n isVerified: true,\n customerId: data.customerId,\n contactId: data.contactId,\n };\n },\n async cartHdrLookup(\n userId: string | number,\n _token: string,\n contactId: string | number,\n customerId: string | number,\n ): Promise<{ cartHdrUid?: number } | null> {\n const result = await augurClient.commerce.cartHdr.lookup.get({\n userId: Number(userId) || 0,\n customerId: Number(customerId) || 0,\n contactId: Number(contactId) || 0,\n });\n return result.data ?? null;\n },\n };\n}\n\n/** Resolve final callbacks: callback overrides take priority over internal SDK calls. */\nfunction resolveCallbacks(\n options: CreateAuthConfigOptions,\n): AugurAuthCallbacks {\n const { augurClient, callbacks } = options;\n\n if (augurClient) {\n const internal = buildInternalCallbacks(augurClient);\n return {\n getUserProfile: callbacks?.getUserProfile ?? internal.getUserProfile,\n cartHdrLookup: callbacks?.cartHdrLookup ?? internal.cartHdrLookup,\n };\n }\n\n if (!callbacks?.getUserProfile) {\n throw new Error(\n \"createAuthConfig requires either `augurClient` or `callbacks.getUserProfile`\",\n );\n }\n\n return {\n getUserProfile: callbacks.getUserProfile,\n cartHdrLookup: callbacks.cartHdrLookup,\n };\n}\n\n/**\n * Create a NextAuth 5 configuration for an Augur ecommerce site.\n *\n * Accepts either an `augurClient` (recommended) for zero-boilerplate auth,\n * or explicit `callbacks` for custom behavior. Callback overrides take\n * priority when both are provided.\n *\n * @example\n * ```ts\n * // Recommended: pass the SDK client directly\n * import NextAuth from \"next-auth\";\n * import { createAuthConfig } from \"@simpleapps-com/augur-server/auth\";\n * import { augurClient } from \"@/lib/augur-client\";\n *\n * export const { handlers, signIn, signOut, auth } = NextAuth(\n * createAuthConfig({\n * augurClient,\n * defaultCustomerId: process.env.NEXT_PUBLIC_DEFAULT_CUSTOMER_ID,\n * defaultContactId: process.env.NEXT_PUBLIC_DEFAULT_CONTACT_ID,\n * }),\n * );\n * ```\n *\n * @example\n * ```ts\n * // Custom callbacks (backward-compatible)\n * import NextAuth from \"next-auth\";\n * import { createAuthConfig } from \"@simpleapps-com/augur-server/auth\";\n *\n * export const { handlers, signIn, signOut, auth } = NextAuth(\n * createAuthConfig({\n * callbacks: { getUserProfile, cartHdrLookup },\n * defaultCustomerId: process.env.NEXT_PUBLIC_DEFAULT_CUSTOMER_ID,\n * }),\n * );\n * ```\n */\nasync function lookupCartHdr(\n siteCallbacks: AugurAuthCallbacks,\n profile: AugurUser,\n defaultCustomerId?: string | number,\n defaultContactId?: string | number,\n): Promise<number | undefined> {\n if (!siteCallbacks.cartHdrLookup || !profile.id) return undefined;\n const cartHdr = await siteCallbacks.cartHdrLookup(\n profile.id,\n \"\",\n profile.contactId ?? defaultContactId ?? \"\",\n profile.customerId ?? defaultCustomerId ?? \"\",\n );\n return cartHdr?.cartHdrUid;\n}\n\nexport function createAuthConfig(\n options: CreateAuthConfigOptions,\n): NextAuthConfig {\n const {\n secret = process.env.NEXT_PUBLIC_AUTH_SECRET,\n maxAge = 4 * 60 * 60,\n defaultCustomerId,\n defaultContactId,\n debug = process.env.NODE_ENV === \"development\",\n } = options;\n\n const siteCallbacks = resolveCallbacks(options);\n\n return {\n providers: [\n Credentials({\n name: \"Credentials\",\n credentials: {\n username: { label: \"Username\", type: \"text\" },\n password: { label: \"Password\", type: \"password\" },\n id: { label: \"ID\", type: \"text\" },\n isVerified: { label: \"Is Verified\", type: \"text\" },\n token: { label: \"Token\", type: \"text\" },\n },\n async authorize(credentials) {\n if (!credentials) return null;\n\n const { id, isVerified, username, token } = credentials as {\n id: string;\n isVerified: string;\n username: string;\n token: string;\n };\n\n return {\n id,\n isVerified: isVerified === \"true\",\n username,\n token,\n };\n },\n }),\n ],\n callbacks: {\n async signIn() {\n return true;\n },\n async redirect({ baseUrl }) {\n return baseUrl;\n },\n async session({ session, token }) {\n const baseUser = {\n id: (token.id as string) || \"\",\n username: (token.username as string) || \"\",\n isVerified: (token.isVerified as boolean) || false,\n };\n\n const buildSession = (userOverrides = {}) => ({\n ...session,\n user: { ...session.user, ...baseUser, ...userOverrides },\n token: token.token as string | undefined,\n });\n\n try {\n const userProfile = await siteCallbacks.getUserProfile(baseUser.id);\n if (!userProfile) return buildSession();\n\n const cartHdrUid = await lookupCartHdr(\n siteCallbacks,\n userProfile,\n defaultCustomerId,\n defaultContactId,\n );\n\n return buildSession({\n name: userProfile.name ?? session.user?.name,\n email: userProfile.email ?? session.user?.email,\n customerId: userProfile.customerId ?? defaultCustomerId,\n contactId: userProfile.contactId,\n cartHdrUid,\n });\n } catch {\n return buildSession();\n }\n },\n async jwt({ token, user }) {\n if (user) {\n const typedUser = user as {\n id: string;\n isVerified: boolean;\n username: string;\n token: string;\n };\n\n return {\n ...token,\n id: typedUser.id,\n isVerified: typedUser.isVerified,\n username: typedUser.username,\n token: typedUser.token,\n };\n }\n return token;\n },\n },\n secret,\n debug,\n session: {\n strategy: \"jwt\",\n maxAge,\n },\n trustHost: true,\n };\n}\n"],"mappings":"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","names":[]}
package/dist/index.js CHANGED
@@ -2,9 +2,6 @@ import {
2
2
  createQueryOptions,
3
3
  createSuspenseQueryOptions
4
4
  } from "./chunk-I26RJDRF.js";
5
- import {
6
- __require
7
- } from "./chunk-DGUM43GV.js";
8
5
 
9
6
  // src/environment.ts
10
7
  function getEnvironment() {
@@ -73,7 +70,7 @@ function getRedisUrl() {
73
70
  if (isStaging) return process.env.REDIS_URL_STAGING;
74
71
  return process.env.REDIS_URL_PROD;
75
72
  }
76
- function getClient() {
73
+ async function getClient() {
77
74
  if (state.client) return state.client;
78
75
  const url = getRedisUrl();
79
76
  if (!url) {
@@ -81,7 +78,7 @@ function getClient() {
81
78
  return null;
82
79
  }
83
80
  try {
84
- const IORedis = __require("ioredis");
81
+ const { default: IORedis } = await import("ioredis");
85
82
  state.client = new IORedis(url, {
86
83
  maxRetriesPerRequest: 1,
87
84
  connectTimeout: 3e3,
@@ -103,7 +100,7 @@ function getClient() {
103
100
  }
104
101
  async function cacheGet(key) {
105
102
  if (isCircuitOpen()) return null;
106
- const client = getClient();
103
+ const client = await getClient();
107
104
  if (!client) return null;
108
105
  try {
109
106
  const value = await client.get(key);
@@ -116,7 +113,7 @@ async function cacheGet(key) {
116
113
  }
117
114
  async function cacheSet(key, value, ttlSeconds) {
118
115
  if (isCircuitOpen()) return;
119
- const client = getClient();
116
+ const client = await getClient();
120
117
  if (!client) return;
121
118
  try {
122
119
  await client.setex(key, ttlSeconds, value);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/environment.ts","../src/cache/redis-client.ts","../src/sdk-call.ts","../src/server-query-client.ts"],"sourcesContent":["/**\n * Environment detection that works across server, client, and containers.\n *\n * Priority:\n * 1. DEPLOYMENT_ENV (\"dev\" → staging, \"live\" → production)\n * 2. Server-side NODE_ENV fallback\n * 3. Client-side hostname detection\n */\nfunction getEnvironment(): \"development\" | \"staging\" | \"production\" {\n const deploymentEnv = process.env.DEPLOYMENT_ENV;\n if (deploymentEnv === \"dev\") return \"staging\";\n if (deploymentEnv === \"live\") return \"production\";\n\n if (typeof window === \"undefined\") {\n if (process.env.NODE_ENV === \"development\") return \"development\";\n return \"production\";\n }\n\n const host = window.location.hostname;\n if (host.includes(\"localhost\") || host.includes(\"127.0.0.1\"))\n return \"development\";\n if (host.includes(\"agr-hosting.dev\")) return \"staging\";\n return \"production\";\n}\n\nexport const env = getEnvironment();\nexport const isDev = env === \"development\";\nexport const isStaging = env === \"staging\";\nexport const isProduction = env === \"production\";\n","import type Redis from \"ioredis\";\nimport { isDev, isStaging } from \"../environment\";\n\nconst CIRCUIT_BREAKER_THRESHOLD = 5;\nconst CIRCUIT_BREAKER_RESET_MS = 60_000;\n\ninterface RedisGlobalState {\n client: Redis | null;\n consecutiveFailures: number;\n circuitOpenUntil: number;\n}\n\nconst g = globalThis as unknown as { __redisState?: RedisGlobalState };\nif (!g.__redisState) {\n g.__redisState = {\n client: null,\n consecutiveFailures: 0,\n circuitOpenUntil: 0,\n };\n}\nconst state = g.__redisState;\n\nconst debugEnabled = isDev || isStaging;\n\nfunction log(...args: unknown[]) {\n if (debugEnabled) {\n console.log(\"[Redis]\", ...args);\n }\n}\n\nfunction isCircuitOpen(): boolean {\n if (state.circuitOpenUntil === 0) return false;\n if (Date.now() >= state.circuitOpenUntil) {\n state.circuitOpenUntil = 0;\n state.consecutiveFailures = 0;\n log(\"Circuit breaker reset -- retrying Redis\");\n return false;\n }\n return true;\n}\n\nfunction recordFailure() {\n state.consecutiveFailures++;\n if (state.consecutiveFailures >= CIRCUIT_BREAKER_THRESHOLD) {\n state.circuitOpenUntil = Date.now() + CIRCUIT_BREAKER_RESET_MS;\n log(\n `Circuit breaker OPEN -- skipping Redis for ${CIRCUIT_BREAKER_RESET_MS / 1000}s`,\n );\n }\n}\n\nfunction recordSuccess() {\n state.consecutiveFailures = 0;\n}\n\nfunction getRedisUrl(): string | undefined {\n const containerRedis = process.env.REDIS_SERVERS;\n if (containerRedis) return `redis://${containerRedis}`;\n\n if (isDev) return process.env.REDIS_URL_DEV;\n if (isStaging) return process.env.REDIS_URL_STAGING;\n return process.env.REDIS_URL_PROD;\n}\n\nfunction getClient(): Redis | null {\n if (state.client) return state.client;\n\n const url = getRedisUrl();\n if (!url) {\n log(\"No REDIS_URL -- cache disabled\");\n return null;\n }\n\n try {\n // Dynamic import at module level isn't possible, so we require ioredis\n // at runtime. It's an optional peer dep -- if not installed, cache is\n // silently disabled.\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const IORedis = require(\"ioredis\") as typeof import(\"ioredis\").default;\n\n state.client = new IORedis(url, {\n maxRetriesPerRequest: 1,\n connectTimeout: 3000,\n lazyConnect: true,\n enableOfflineQueue: false,\n });\n\n state.client.on(\"error\", (err: Error) => {\n log(\"Connection error:\", err.message);\n recordFailure();\n });\n\n state.client.on(\"connect\", () => log(\"Connected\"));\n\n state.client.connect().catch(() => {\n /* handled by error event */\n });\n\n return state.client;\n } catch {\n log(\"Failed to create client (ioredis not installed?)\");\n return null;\n }\n}\n\nexport async function cacheGet(key: string): Promise<string | null> {\n if (isCircuitOpen()) return null;\n\n const client = getClient();\n if (!client) return null;\n\n try {\n const value = await client.get(key);\n recordSuccess();\n return value;\n } catch {\n recordFailure();\n return null;\n }\n}\n\nexport async function cacheSet(\n key: string,\n value: string,\n ttlSeconds: number,\n): Promise<void> {\n if (isCircuitOpen()) return;\n\n const client = getClient();\n if (!client) return;\n\n try {\n await client.setex(key, ttlSeconds, value);\n recordSuccess();\n } catch {\n recordFailure();\n }\n}\n\nexport function getCircuitState(): \"closed\" | \"open\" {\n return isCircuitOpen() ? \"open\" : \"closed\";\n}\n\nexport function isRedisConnected(): boolean {\n return state.client?.status === \"ready\";\n}\n","/**\n * Calls an Augur SDK method, forwarding all arguments with full type safety.\n *\n * With augur-api >= 0.9.6, SDK methods properly declare their `CacheParams`\n * option (including `edgeCache`), so this wrapper preserves both parameter\n * and return-type inference end-to-end.\n *\n * @example\n * ```ts\n * const result = await sdkCall(\n * augurServices.items.invMast.get,\n * invMastUid,\n * { edgeCache: 4 },\n * );\n * ```\n */\nexport async function sdkCall<TArgs extends unknown[], TResult>(\n method: (...args: TArgs) => Promise<TResult>,\n ...args: TArgs\n): Promise<TResult> {\n return method(...args);\n}\n","import { cache } from \"react\";\nimport { QueryClient } from \"@tanstack/react-query\";\nimport { CACHE_CONFIG } from \"@simpleapps-com/augur-utils\";\n\n/**\n * Creates a server-side query client optimised for prefetching.\n *\n * - No persistence (server-only)\n * - Longer cache times for prefetched data\n * - No retries (fail fast on server)\n * - No refetching (server renders are one-shot)\n */\nexport function createServerQueryClient(): QueryClient {\n return new QueryClient({\n defaultOptions: {\n queries: {\n staleTime: CACHE_CONFIG.STATIC.staleTime,\n gcTime: CACHE_CONFIG.STATIC.staleTime,\n retry: 0,\n refetchOnMount: false,\n refetchOnWindowFocus: false,\n refetchOnReconnect: false,\n },\n },\n });\n}\n\n/**\n * Returns a per-request singleton QueryClient for React Server Components.\n *\n * React's `cache()` deduplicates calls within a single server request,\n * so each request gets its own QueryClient while avoiding the cross-request\n * state leakage that a module-level singleton would cause.\n */\nexport const getServerQueryClient = cache(\n (): QueryClient => createServerQueryClient(),\n);\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/environment.ts","../src/cache/redis-client.ts","../src/sdk-call.ts","../src/server-query-client.ts"],"sourcesContent":["/**\n * Environment detection that works across server, client, and containers.\n *\n * Priority:\n * 1. DEPLOYMENT_ENV (\"dev\" → staging, \"live\" → production)\n * 2. Server-side NODE_ENV fallback\n * 3. Client-side hostname detection\n */\nfunction getEnvironment(): \"development\" | \"staging\" | \"production\" {\n const deploymentEnv = process.env.DEPLOYMENT_ENV;\n if (deploymentEnv === \"dev\") return \"staging\";\n if (deploymentEnv === \"live\") return \"production\";\n\n if (typeof window === \"undefined\") {\n if (process.env.NODE_ENV === \"development\") return \"development\";\n return \"production\";\n }\n\n const host = window.location.hostname;\n if (host.includes(\"localhost\") || host.includes(\"127.0.0.1\"))\n return \"development\";\n if (host.includes(\"agr-hosting.dev\")) return \"staging\";\n return \"production\";\n}\n\nexport const env = getEnvironment();\nexport const isDev = env === \"development\";\nexport const isStaging = env === \"staging\";\nexport const isProduction = env === \"production\";\n","import type Redis from \"ioredis\";\nimport { isDev, isStaging } from \"../environment\";\n\nconst CIRCUIT_BREAKER_THRESHOLD = 5;\nconst CIRCUIT_BREAKER_RESET_MS = 60_000;\n\ninterface RedisGlobalState {\n client: Redis | null;\n consecutiveFailures: number;\n circuitOpenUntil: number;\n}\n\nconst g = globalThis as unknown as { __redisState?: RedisGlobalState };\nif (!g.__redisState) {\n g.__redisState = {\n client: null,\n consecutiveFailures: 0,\n circuitOpenUntil: 0,\n };\n}\nconst state = g.__redisState;\n\nconst debugEnabled = isDev || isStaging;\n\nfunction log(...args: unknown[]) {\n if (debugEnabled) {\n console.log(\"[Redis]\", ...args);\n }\n}\n\nfunction isCircuitOpen(): boolean {\n if (state.circuitOpenUntil === 0) return false;\n if (Date.now() >= state.circuitOpenUntil) {\n state.circuitOpenUntil = 0;\n state.consecutiveFailures = 0;\n log(\"Circuit breaker reset -- retrying Redis\");\n return false;\n }\n return true;\n}\n\nfunction recordFailure() {\n state.consecutiveFailures++;\n if (state.consecutiveFailures >= CIRCUIT_BREAKER_THRESHOLD) {\n state.circuitOpenUntil = Date.now() + CIRCUIT_BREAKER_RESET_MS;\n log(\n `Circuit breaker OPEN -- skipping Redis for ${CIRCUIT_BREAKER_RESET_MS / 1000}s`,\n );\n }\n}\n\nfunction recordSuccess() {\n state.consecutiveFailures = 0;\n}\n\nfunction getRedisUrl(): string | undefined {\n const containerRedis = process.env.REDIS_SERVERS;\n if (containerRedis) return `redis://${containerRedis}`;\n\n if (isDev) return process.env.REDIS_URL_DEV;\n if (isStaging) return process.env.REDIS_URL_STAGING;\n return process.env.REDIS_URL_PROD;\n}\n\nasync function getClient(): Promise<Redis | null> {\n if (state.client) return state.client;\n\n const url = getRedisUrl();\n if (!url) {\n log(\"No REDIS_URL -- cache disabled\");\n return null;\n }\n\n try {\n // Dynamic import so the built ESM output doesn't use esbuild's __require\n // shim, which breaks in pure ESM environments (Next.js 16 + Turbopack).\n // ioredis is CJS-only; Node wraps its module.exports as { default }.\n const { default: IORedis } = await import(\"ioredis\");\n\n state.client = new IORedis(url, {\n maxRetriesPerRequest: 1,\n connectTimeout: 3000,\n lazyConnect: true,\n enableOfflineQueue: false,\n });\n\n state.client.on(\"error\", (err: Error) => {\n log(\"Connection error:\", err.message);\n recordFailure();\n });\n\n state.client.on(\"connect\", () => log(\"Connected\"));\n\n state.client.connect().catch(() => {\n /* handled by error event */\n });\n\n return state.client;\n } catch {\n log(\"Failed to create client (ioredis not installed?)\");\n return null;\n }\n}\n\nexport async function cacheGet(key: string): Promise<string | null> {\n if (isCircuitOpen()) return null;\n\n const client = await getClient();\n if (!client) return null;\n\n try {\n const value = await client.get(key);\n recordSuccess();\n return value;\n } catch {\n recordFailure();\n return null;\n }\n}\n\nexport async function cacheSet(\n key: string,\n value: string,\n ttlSeconds: number,\n): Promise<void> {\n if (isCircuitOpen()) return;\n\n const client = await getClient();\n if (!client) return;\n\n try {\n await client.setex(key, ttlSeconds, value);\n recordSuccess();\n } catch {\n recordFailure();\n }\n}\n\nexport function getCircuitState(): \"closed\" | \"open\" {\n return isCircuitOpen() ? \"open\" : \"closed\";\n}\n\nexport function isRedisConnected(): boolean {\n return state.client?.status === \"ready\";\n}\n","/**\n * Calls an Augur SDK method, forwarding all arguments with full type safety.\n *\n * With augur-api >= 0.9.6, SDK methods properly declare their `CacheParams`\n * option (including `edgeCache`), so this wrapper preserves both parameter\n * and return-type inference end-to-end.\n *\n * @example\n * ```ts\n * const result = await sdkCall(\n * augurServices.items.invMast.get,\n * invMastUid,\n * { edgeCache: 4 },\n * );\n * ```\n */\nexport async function sdkCall<TArgs extends unknown[], TResult>(\n method: (...args: TArgs) => Promise<TResult>,\n ...args: TArgs\n): Promise<TResult> {\n return method(...args);\n}\n","import { cache } from \"react\";\nimport { QueryClient } from \"@tanstack/react-query\";\nimport { CACHE_CONFIG } from \"@simpleapps-com/augur-utils\";\n\n/**\n * Creates a server-side query client optimised for prefetching.\n *\n * - No persistence (server-only)\n * - Longer cache times for prefetched data\n * - No retries (fail fast on server)\n * - No refetching (server renders are one-shot)\n */\nexport function createServerQueryClient(): QueryClient {\n return new QueryClient({\n defaultOptions: {\n queries: {\n staleTime: CACHE_CONFIG.STATIC.staleTime,\n gcTime: CACHE_CONFIG.STATIC.staleTime,\n retry: 0,\n refetchOnMount: false,\n refetchOnWindowFocus: false,\n refetchOnReconnect: false,\n },\n },\n });\n}\n\n/**\n * Returns a per-request singleton QueryClient for React Server Components.\n *\n * React's `cache()` deduplicates calls within a single server request,\n * so each request gets its own QueryClient while avoiding the cross-request\n * state leakage that a module-level singleton would cause.\n */\nexport const getServerQueryClient = cache(\n (): QueryClient => createServerQueryClient(),\n);\n"],"mappings":"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","names":[]}
package/dist/query.js CHANGED
@@ -2,7 +2,6 @@ import {
2
2
  createQueryOptions,
3
3
  createSuspenseQueryOptions
4
4
  } from "./chunk-I26RJDRF.js";
5
- import "./chunk-DGUM43GV.js";
6
5
  export {
7
6
  createQueryOptions,
8
7
  createSuspenseQueryOptions
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simpleapps-com/augur-server",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Server-side utilities for Augur ecommerce sites (Redis caching, SDK helpers, auth)",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -33,7 +33,7 @@
33
33
  ],
34
34
  "dependencies": {
35
35
  "valibot": "^1.0.0",
36
- "@simpleapps-com/augur-utils": "0.2.0"
36
+ "@simpleapps-com/augur-utils": "0.2.1"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@simpleapps-com/augur-api": "^0.9.6",
@@ -1,11 +0,0 @@
1
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
- }) : x)(function(x) {
4
- if (typeof require !== "undefined") return require.apply(this, arguments);
5
- throw Error('Dynamic require of "' + x + '" is not supported');
6
- });
7
-
8
- export {
9
- __require
10
- };
11
- //# sourceMappingURL=chunk-DGUM43GV.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}