@replanejs/next 0.7.0

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/provider.tsx","../src/script.tsx"],"sourcesContent":[],"mappings":";;;;;;;;;;UAMiB,wBAAA;;AAAjB;AAoCA;;EAAyC,OAKb,EAAA,MAAA;EAAC;;;;EA2BR,MAAA,EAAA,MAAA;;;;ACrBrB;EAAmC,gBAAA,CAAA,EAAA,MAAA;EAAA;;;;EAIzB,YACkB,CAAA,EAAA,MAAA;EAAC;;AAAC;;;;ACrD0B;AAG9B;AAGH;AAAA,UF+BN,wBE/BM,CAAA,UAAA,MAAA,GAAA,GAAA,CAAA,CAAA;EAAA;;;;EAIE,QAAA,EFgCb,iBEhCa,CFgCG,CEhCH,CAAA;EAqCT;;;;AAAoE;AASpF;;;;;AAaqB;AAyBrB;;;;;;EAI6B,UAAA,CAAA,EFrCd,wBEqCc;EAAA;;;;YF/BjB;YAEA;;;;;;;;;;;AApEZ;AAoCA;;;;;;;AAgCqB;;;;ACrBrB;;;;;;;;;AAK8B;;;;ACrD0B;AAG9B;AAGH;;;;;;AAIE;AAqCzB;;;;AAAoF;AASpF;AAA2C,iBDR3B,mBCQ2B,CAAA,UAAA,MAAA,CAAA,CAAA;EAAA,QAAA;EAAA,UAAA;EAAA,OAAA;EAAA;AAAA,CAAA,EDHxC,wBCGwC,CDHf,CCGe,CAAA,CAAA,EDHb,oBAAA,CAAA,GAAA,CAAA,OCGa;;;;cArDrC,oBAAA;KAGD,SAAA,GAAY;;;IFLA,CESZ,oBAAA,EFToC,EESZ,iBFTY,CESI,SFTJ,CAAA;EAoCxB;;;;;;;AAgCI;;;;ACrBrB;;;;;;;;;AAK8B;;;;ACrD0B;AAG9B;AAGH;;;;;;AAIE;AAqCzB;;AAAqF,iBAArE,wBAAqE,CAAA,UAAA,MAAA,CAAA,CAAA,QAAA,EAAhB,iBAAgB,CAAA,CAAA,CAAA,CAAA,EAAA,MAAA;;AAAD;AASpF;AAA2C,UAA1B,0BAAA,CAA0B;EAAA;;;AAatB;EAyBL,UAAA,CAAA,EAjCD,wBAiCsB;EAAA;;;;EAG3B,QACP,CAAA,EA/BU,SA+BV;EAA0B,QAAA,EA7BjB,SA6BiB;AAAA;;;;;;;;;;;;;;;;;;;;;;;iBAJb,qBAAA;;;;GAIb,6BAA0B,kBAAA,CAAA,GAAA,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,198 @@
1
+ import { useEffect, useMemo, useRef, useState } from "react";
2
+ import { ReplaneProvider, useConfig, useReplane } from "@replanejs/react";
3
+ import { restoreReplaneClient, restoreReplaneClient as restoreReplaneClient$1 } from "@replanejs/sdk";
4
+ import { Fragment, jsx } from "react/jsx-runtime";
5
+
6
+ //#region src/provider.tsx
7
+ /**
8
+ * Next.js-optimized Replane provider with SSR hydration support.
9
+ *
10
+ * This component:
11
+ * 1. Restores the Replane client from a server-side snapshot instantly (no loading state)
12
+ * 2. Optionally connects to Replane for real-time updates
13
+ * 3. Preserves the client across re-renders for minimal latency
14
+ *
15
+ * @example
16
+ * ```tsx
17
+ * // app/layout.tsx
18
+ * import { getReplaneSnapshot } from "@replanejs/next/server";
19
+ * import { ReplaneNextProvider } from "@replanejs/next";
20
+ *
21
+ * export default async function RootLayout({ children }) {
22
+ * const snapshot = await getReplaneSnapshot({
23
+ * baseUrl: process.env.REPLANE_BASE_URL!,
24
+ * sdkKey: process.env.REPLANE_SDK_KEY!,
25
+ * });
26
+ *
27
+ * return (
28
+ * <html>
29
+ * <body>
30
+ * <ReplaneNextProvider
31
+ * snapshot={snapshot}
32
+ * connection={{
33
+ * baseUrl: process.env.NEXT_PUBLIC_REPLANE_BASE_URL!,
34
+ * sdkKey: process.env.NEXT_PUBLIC_REPLANE_SDK_KEY!,
35
+ * }}
36
+ * >
37
+ * {children}
38
+ * </ReplaneNextProvider>
39
+ * </body>
40
+ * </html>
41
+ * );
42
+ * }
43
+ * ```
44
+ *
45
+ * @example
46
+ * ```tsx
47
+ * // Without real-time updates (static snapshot only)
48
+ * <ReplaneNextProvider snapshot={snapshot}>
49
+ * {children}
50
+ * </ReplaneNextProvider>
51
+ * ```
52
+ */
53
+ function ReplaneNextProvider({ snapshot, connection, context, children }) {
54
+ const clientRef = useRef(null);
55
+ const clientKey = useMemo(() => {
56
+ const snapshotKey = JSON.stringify(snapshot.configs.map((c) => c.name).sort());
57
+ const connectionKey = connection ? `${connection.baseUrl}:${connection.sdkKey}` : "no-connection";
58
+ const contextKey = context ? JSON.stringify(context) : "no-context";
59
+ return `${snapshotKey}:${connectionKey}:${contextKey}`;
60
+ }, [
61
+ snapshot,
62
+ connection,
63
+ context
64
+ ]);
65
+ const client = useMemo(() => {
66
+ if (clientRef.current) {}
67
+ const newClient = restoreReplaneClient$1({
68
+ snapshot,
69
+ connection: connection ? {
70
+ baseUrl: connection.baseUrl,
71
+ sdkKey: connection.sdkKey,
72
+ requestTimeoutMs: connection.requestTimeoutMs,
73
+ retryDelayMs: connection.retryDelayMs,
74
+ inactivityTimeoutMs: connection.inactivityTimeoutMs
75
+ } : void 0,
76
+ context
77
+ });
78
+ clientRef.current = newClient;
79
+ return newClient;
80
+ }, [clientKey]);
81
+ useEffect(() => {
82
+ return () => {
83
+ if (clientRef.current) {
84
+ clientRef.current.close();
85
+ clientRef.current = null;
86
+ }
87
+ };
88
+ }, []);
89
+ return /* @__PURE__ */ jsx(ReplaneProvider, {
90
+ client,
91
+ children
92
+ });
93
+ }
94
+
95
+ //#endregion
96
+ //#region src/script.tsx
97
+ const REPLANE_SNAPSHOT_KEY = "__REPLANE_SNAPSHOT__";
98
+ /**
99
+ * Generate the script content for embedding the snapshot.
100
+ *
101
+ * Use this in a Server Component to embed the snapshot in the page:
102
+ *
103
+ * @example
104
+ * ```tsx
105
+ * // app/layout.tsx
106
+ * import { getReplaneSnapshot } from "@replanejs/next/server";
107
+ * import { getReplaneSnapshotScript, ReplaneScriptProvider } from "@replanejs/next";
108
+ *
109
+ * export default async function RootLayout({ children }) {
110
+ * const snapshot = await getReplaneSnapshot({ ... });
111
+ *
112
+ * return (
113
+ * <html>
114
+ * <head>
115
+ * <script
116
+ * dangerouslySetInnerHTML={{
117
+ * __html: getReplaneSnapshotScript(snapshot),
118
+ * }}
119
+ * />
120
+ * </head>
121
+ * <body>
122
+ * <ReplaneScriptProvider connection={{ ... }}>
123
+ * {children}
124
+ * </ReplaneScriptProvider>
125
+ * </body>
126
+ * </html>
127
+ * );
128
+ * }
129
+ * ```
130
+ */
131
+ function getReplaneSnapshotScript(snapshot) {
132
+ const json = JSON.stringify(snapshot).replace(/<\/script>/gi, "<\\/script>");
133
+ return `window.${REPLANE_SNAPSHOT_KEY}=${json};`;
134
+ }
135
+ /**
136
+ * Provider that reads the snapshot from a script tag.
137
+ *
138
+ * Use this with `getReplaneSnapshotScript()` for an alternative hydration pattern
139
+ * where the snapshot is embedded in a script tag instead of passed as a prop.
140
+ *
141
+ * This pattern can be useful for:
142
+ * - Pages with heavy component trees where prop drilling is inconvenient
143
+ * - Partial hydration scenarios
144
+ * - When you want the snapshot to be available before React hydrates
145
+ *
146
+ * @example
147
+ * ```tsx
148
+ * // In app/layout.tsx (Server Component)
149
+ * <script dangerouslySetInnerHTML={{ __html: getReplaneSnapshotScript(snapshot) }} />
150
+ *
151
+ * // In a client component
152
+ * <ReplaneScriptProvider connection={{ baseUrl, sdkKey }}>
153
+ * <App />
154
+ * </ReplaneScriptProvider>
155
+ * ```
156
+ */
157
+ function ReplaneScriptProvider({ connection, fallback, children }) {
158
+ const [snapshot, setSnapshot] = useState(() => {
159
+ if (typeof window !== "undefined" && window[REPLANE_SNAPSHOT_KEY]) return window[REPLANE_SNAPSHOT_KEY];
160
+ return null;
161
+ });
162
+ const clientRef = useRef(null);
163
+ useEffect(() => {
164
+ if (!snapshot && typeof window !== "undefined" && window[REPLANE_SNAPSHOT_KEY]) setSnapshot(window[REPLANE_SNAPSHOT_KEY]);
165
+ }, [snapshot]);
166
+ const client = useMemo(() => {
167
+ if (!snapshot) return null;
168
+ const newClient = restoreReplaneClient$1({
169
+ snapshot,
170
+ connection: connection ? {
171
+ baseUrl: connection.baseUrl,
172
+ sdkKey: connection.sdkKey,
173
+ requestTimeoutMs: connection.requestTimeoutMs,
174
+ retryDelayMs: connection.retryDelayMs,
175
+ inactivityTimeoutMs: connection.inactivityTimeoutMs
176
+ } : void 0
177
+ });
178
+ clientRef.current = newClient;
179
+ return newClient;
180
+ }, [snapshot, connection]);
181
+ useEffect(() => {
182
+ return () => {
183
+ if (clientRef.current) {
184
+ clientRef.current.close();
185
+ clientRef.current = null;
186
+ }
187
+ };
188
+ }, []);
189
+ if (!client) return /* @__PURE__ */ jsx(Fragment, { children: fallback ?? null });
190
+ return /* @__PURE__ */ jsx(ReplaneProvider, {
191
+ client,
192
+ children
193
+ });
194
+ }
195
+
196
+ //#endregion
197
+ export { ReplaneNextProvider, ReplaneScriptProvider, getReplaneSnapshotScript, restoreReplaneClient, useConfig, useReplane };
198
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["snapshot: ReplaneSnapshot<T>"],"sources":["../src/provider.tsx","../src/script.tsx"],"sourcesContent":["\"use client\";\n\nimport { useMemo, useRef, useEffect } from \"react\";\nimport { ReplaneProvider } from \"@replanejs/react\";\nimport { restoreReplaneClient, type ReplaneClient } from \"@replanejs/sdk\";\nimport type { ReplaneNextProviderProps } from \"./types\";\n\n/**\n * Next.js-optimized Replane provider with SSR hydration support.\n *\n * This component:\n * 1. Restores the Replane client from a server-side snapshot instantly (no loading state)\n * 2. Optionally connects to Replane for real-time updates\n * 3. Preserves the client across re-renders for minimal latency\n *\n * @example\n * ```tsx\n * // app/layout.tsx\n * import { getReplaneSnapshot } from \"@replanejs/next/server\";\n * import { ReplaneNextProvider } from \"@replanejs/next\";\n *\n * export default async function RootLayout({ children }) {\n * const snapshot = await getReplaneSnapshot({\n * baseUrl: process.env.REPLANE_BASE_URL!,\n * sdkKey: process.env.REPLANE_SDK_KEY!,\n * });\n *\n * return (\n * <html>\n * <body>\n * <ReplaneNextProvider\n * snapshot={snapshot}\n * connection={{\n * baseUrl: process.env.NEXT_PUBLIC_REPLANE_BASE_URL!,\n * sdkKey: process.env.NEXT_PUBLIC_REPLANE_SDK_KEY!,\n * }}\n * >\n * {children}\n * </ReplaneNextProvider>\n * </body>\n * </html>\n * );\n * }\n * ```\n *\n * @example\n * ```tsx\n * // Without real-time updates (static snapshot only)\n * <ReplaneNextProvider snapshot={snapshot}>\n * {children}\n * </ReplaneNextProvider>\n * ```\n */\nexport function ReplaneNextProvider<T extends object>({\n snapshot,\n connection,\n context,\n children,\n}: ReplaneNextProviderProps<T>) {\n // Use a ref to store the client to preserve it across re-renders\n // This is important for minimizing latency - we don't want to recreate\n // the client on every render\n const clientRef = useRef<ReplaneClient<T> | null>(null);\n\n // Create a stable key for the client based on snapshot and connection\n // We only recreate the client if these change\n const clientKey = useMemo(() => {\n const snapshotKey = JSON.stringify(snapshot.configs.map((c) => c.name).sort());\n const connectionKey = connection ? `${connection.baseUrl}:${connection.sdkKey}` : \"no-connection\";\n const contextKey = context ? JSON.stringify(context) : \"no-context\";\n return `${snapshotKey}:${connectionKey}:${contextKey}`;\n }, [snapshot, connection, context]);\n\n // Memoize client creation\n const client = useMemo(() => {\n // If we have a cached client with the same key, reuse it\n if (clientRef.current) {\n // Check if we need to create a new client\n // For simplicity, we always create a new client if the key changes\n // This happens when snapshot or connection changes\n }\n\n const newClient = restoreReplaneClient<T>({\n snapshot,\n connection: connection\n ? {\n baseUrl: connection.baseUrl,\n sdkKey: connection.sdkKey,\n requestTimeoutMs: connection.requestTimeoutMs,\n retryDelayMs: connection.retryDelayMs,\n inactivityTimeoutMs: connection.inactivityTimeoutMs,\n }\n : undefined,\n context,\n });\n\n clientRef.current = newClient;\n return newClient;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [clientKey]);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n if (clientRef.current) {\n clientRef.current.close();\n clientRef.current = null;\n }\n };\n }, []);\n\n return <ReplaneProvider client={client}>{children}</ReplaneProvider>;\n}\n","\"use client\";\n\nimport { useEffect, useState, useMemo, useRef, type ReactNode } from \"react\";\nimport { ReplaneProvider } from \"@replanejs/react\";\nimport { restoreReplaneClient, type ReplaneSnapshot, type ReplaneClient } from \"@replanejs/sdk\";\nimport type { ReplaneConnectionOptions } from \"./types\";\n\n// Global variable name for the snapshot\nconst REPLANE_SNAPSHOT_KEY = \"__REPLANE_SNAPSHOT__\";\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyConfig = Record<string, any>;\n\ndeclare global {\n interface Window {\n [REPLANE_SNAPSHOT_KEY]?: ReplaneSnapshot<AnyConfig>;\n }\n}\n\n/**\n * Generate the script content for embedding the snapshot.\n *\n * Use this in a Server Component to embed the snapshot in the page:\n *\n * @example\n * ```tsx\n * // app/layout.tsx\n * import { getReplaneSnapshot } from \"@replanejs/next/server\";\n * import { getReplaneSnapshotScript, ReplaneScriptProvider } from \"@replanejs/next\";\n *\n * export default async function RootLayout({ children }) {\n * const snapshot = await getReplaneSnapshot({ ... });\n *\n * return (\n * <html>\n * <head>\n * <script\n * dangerouslySetInnerHTML={{\n * __html: getReplaneSnapshotScript(snapshot),\n * }}\n * />\n * </head>\n * <body>\n * <ReplaneScriptProvider connection={{ ... }}>\n * {children}\n * </ReplaneScriptProvider>\n * </body>\n * </html>\n * );\n * }\n * ```\n */\nexport function getReplaneSnapshotScript<T extends object>(snapshot: ReplaneSnapshot<T>): string {\n // Escape script closing tags in JSON to prevent XSS\n const json = JSON.stringify(snapshot).replace(/<\\/script>/gi, \"<\\\\/script>\");\n return `window.${REPLANE_SNAPSHOT_KEY}=${json};`;\n}\n\n/**\n * Props for ReplaneScriptProvider.\n */\nexport interface ReplaneScriptProviderProps {\n /**\n * Connection options for real-time updates.\n * If not provided, the client will only use the snapshot data (no live updates).\n */\n connection?: ReplaneConnectionOptions;\n\n /**\n * Fallback to render while waiting for the snapshot.\n * This should rarely be needed since the script is in the head.\n */\n fallback?: ReactNode;\n\n children: ReactNode;\n}\n\n/**\n * Provider that reads the snapshot from a script tag.\n *\n * Use this with `getReplaneSnapshotScript()` for an alternative hydration pattern\n * where the snapshot is embedded in a script tag instead of passed as a prop.\n *\n * This pattern can be useful for:\n * - Pages with heavy component trees where prop drilling is inconvenient\n * - Partial hydration scenarios\n * - When you want the snapshot to be available before React hydrates\n *\n * @example\n * ```tsx\n * // In app/layout.tsx (Server Component)\n * <script dangerouslySetInnerHTML={{ __html: getReplaneSnapshotScript(snapshot) }} />\n *\n * // In a client component\n * <ReplaneScriptProvider connection={{ baseUrl, sdkKey }}>\n * <App />\n * </ReplaneScriptProvider>\n * ```\n */\nexport function ReplaneScriptProvider({\n connection,\n fallback,\n children,\n}: ReplaneScriptProviderProps) {\n const [snapshot, setSnapshot] = useState<ReplaneSnapshot<AnyConfig> | null>(() => {\n // Try to get snapshot from window on initial render (SSR-safe)\n if (typeof window !== \"undefined\" && window[REPLANE_SNAPSHOT_KEY]) {\n return window[REPLANE_SNAPSHOT_KEY];\n }\n return null;\n });\n\n const clientRef = useRef<ReplaneClient<AnyConfig> | null>(null);\n\n // Check for snapshot on mount (in case the script runs after initial render)\n useEffect(() => {\n if (!snapshot && typeof window !== \"undefined\" && window[REPLANE_SNAPSHOT_KEY]) {\n setSnapshot(window[REPLANE_SNAPSHOT_KEY]);\n }\n }, [snapshot]);\n\n // Create client from snapshot\n const client = useMemo(() => {\n if (!snapshot) return null;\n\n const newClient = restoreReplaneClient({\n snapshot,\n connection: connection\n ? {\n baseUrl: connection.baseUrl,\n sdkKey: connection.sdkKey,\n requestTimeoutMs: connection.requestTimeoutMs,\n retryDelayMs: connection.retryDelayMs,\n inactivityTimeoutMs: connection.inactivityTimeoutMs,\n }\n : undefined,\n });\n\n clientRef.current = newClient;\n return newClient;\n }, [snapshot, connection]);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n if (clientRef.current) {\n clientRef.current.close();\n clientRef.current = null;\n }\n };\n }, []);\n\n if (!client) {\n return <>{fallback ?? null}</>;\n }\n\n return <ReplaneProvider client={client}>{children}</ReplaneProvider>;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqDA,SAAgB,oBAAsC,EACpD,UACA,YACA,SACA,UAC4B,EAAE;CAI9B,MAAM,YAAY,OAAgC,KAAK;CAIvD,MAAM,YAAY,QAAQ,MAAM;EAC9B,MAAM,cAAc,KAAK,UAAU,SAAS,QAAQ,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC;EAC9E,MAAM,gBAAgB,cAAc,EAAE,WAAW,QAAQ,GAAG,WAAW,OAAO,IAAI;EAClF,MAAM,aAAa,UAAU,KAAK,UAAU,QAAQ,GAAG;AACvD,UAAQ,EAAE,YAAY,GAAG,cAAc,GAAG,WAAW;CACtD,GAAE;EAAC;EAAU;EAAY;CAAQ,EAAC;CAGnC,MAAM,SAAS,QAAQ,MAAM;AAE3B,MAAI,UAAU,SAAS,CAItB;EAED,MAAM,YAAY,uBAAwB;GACxC;GACA,YAAY,aACR;IACE,SAAS,WAAW;IACpB,QAAQ,WAAW;IACnB,kBAAkB,WAAW;IAC7B,cAAc,WAAW;IACzB,qBAAqB,WAAW;GACjC;GAEL;EACD,EAAC;AAEF,YAAU,UAAU;AACpB,SAAO;CAER,GAAE,CAAC,SAAU,EAAC;AAGf,WAAU,MAAM;AACd,SAAO,MAAM;AACX,OAAI,UAAU,SAAS;AACrB,cAAU,QAAQ,OAAO;AACzB,cAAU,UAAU;GACrB;EACF;CACF,GAAE,CAAE,EAAC;AAEN,wBAAO,IAAC;EAAwB;EAAS;GAA2B;AACrE;;;;ACxGD,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4C7B,SAAgB,yBAA2CA,UAAsC;CAE/F,MAAM,OAAO,KAAK,UAAU,SAAS,CAAC,QAAQ,gBAAgB,cAAc;AAC5E,SAAQ,SAAS,qBAAqB,GAAG,KAAK;AAC/C;;;;;;;;;;;;;;;;;;;;;;;AA2CD,SAAgB,sBAAsB,EACpC,YACA,UACA,UAC2B,EAAE;CAC7B,MAAM,CAAC,UAAU,YAAY,GAAG,SAA4C,MAAM;AAEhF,aAAW,WAAW,eAAe,OAAO,sBAC1C,QAAO,OAAO;AAEhB,SAAO;CACR,EAAC;CAEF,MAAM,YAAY,OAAwC,KAAK;AAG/D,WAAU,MAAM;AACd,OAAK,mBAAmB,WAAW,eAAe,OAAO,sBACvD,aAAY,OAAO,sBAAsB;CAE5C,GAAE,CAAC,QAAS,EAAC;CAGd,MAAM,SAAS,QAAQ,MAAM;AAC3B,OAAK,SAAU,QAAO;EAEtB,MAAM,YAAY,uBAAqB;GACrC;GACA,YAAY,aACR;IACE,SAAS,WAAW;IACpB,QAAQ,WAAW;IACnB,kBAAkB,WAAW;IAC7B,cAAc,WAAW;IACzB,qBAAqB,WAAW;GACjC;EAEN,EAAC;AAEF,YAAU,UAAU;AACpB,SAAO;CACR,GAAE,CAAC,UAAU,UAAW,EAAC;AAG1B,WAAU,MAAM;AACd,SAAO,MAAM;AACX,OAAI,UAAU,SAAS;AACrB,cAAU,QAAQ,OAAO;AACzB,cAAU,UAAU;GACrB;EACF;CACF,GAAE,CAAE,EAAC;AAEN,MAAK,OACH,wBAAO,0BAAG,YAAY,OAAQ;AAGhC,wBAAO,IAAC;EAAwB;EAAS;GAA2B;AACrE"}
@@ -0,0 +1,95 @@
1
+ const require_chunk = require('./chunk-CUT6urMc.cjs');
2
+ const __replanejs_sdk = require_chunk.__toESM(require("@replanejs/sdk"));
3
+
4
+ //#region src/server.ts
5
+ /**
6
+ * Fetch configs from Replane and return a serializable snapshot.
7
+ *
8
+ * This is the primary server-side function for Next.js integration.
9
+ * It creates a Replane client, waits for initialization, captures a snapshot,
10
+ * and closes the client.
11
+ *
12
+ * The snapshot can be passed to `ReplaneNextProvider` for client-side hydration.
13
+ *
14
+ * @example
15
+ * ```tsx
16
+ * // In a Server Component
17
+ * const snapshot = await getReplaneSnapshot({
18
+ * baseUrl: process.env.REPLANE_BASE_URL!,
19
+ * sdkKey: process.env.REPLANE_SDK_KEY!,
20
+ * context: { userId: user.id },
21
+ * });
22
+ * ```
23
+ *
24
+ * @example
25
+ * ```tsx
26
+ * // With Next.js caching
27
+ * const snapshot = await getReplaneSnapshot({
28
+ * baseUrl: process.env.REPLANE_BASE_URL!,
29
+ * sdkKey: process.env.REPLANE_SDK_KEY!,
30
+ * fetchFn: (url, init) => fetch(url, {
31
+ * ...init,
32
+ * next: { revalidate: 60 }, // Revalidate every 60 seconds
33
+ * }),
34
+ * });
35
+ * ```
36
+ */
37
+ async function getReplaneSnapshot(options) {
38
+ const client = await (0, __replanejs_sdk.createReplaneClient)({
39
+ baseUrl: options.baseUrl,
40
+ sdkKey: options.sdkKey,
41
+ fetchFn: options.fetchFn,
42
+ requestTimeoutMs: options.requestTimeoutMs,
43
+ initializationTimeoutMs: options.initializationTimeoutMs,
44
+ context: options.context,
45
+ required: options.required,
46
+ fallbacks: options.fallbacks
47
+ });
48
+ try {
49
+ return client.getSnapshot();
50
+ } finally {
51
+ client.close();
52
+ }
53
+ }
54
+ /**
55
+ * Get a config value directly on the server.
56
+ *
57
+ * This is useful when you need a single config value in a Server Component
58
+ * or server-side code and don't need the full snapshot/hydration flow.
59
+ *
60
+ * Note: This creates a new client for each call, so prefer `getReplaneSnapshot`
61
+ * if you need multiple configs or client-side hydration.
62
+ *
63
+ * @example
64
+ * ```tsx
65
+ * // In a Server Component
66
+ * const maintenanceMode = await getConfig<boolean>({
67
+ * name: "maintenance-mode",
68
+ * baseUrl: process.env.REPLANE_BASE_URL!,
69
+ * sdkKey: process.env.REPLANE_SDK_KEY!,
70
+ * });
71
+ *
72
+ * if (maintenanceMode) {
73
+ * return <MaintenancePage />;
74
+ * }
75
+ * ```
76
+ */
77
+ async function getConfig(options) {
78
+ const client = await (0, __replanejs_sdk.createReplaneClient)({
79
+ baseUrl: options.baseUrl,
80
+ sdkKey: options.sdkKey,
81
+ fetchFn: options.fetchFn,
82
+ requestTimeoutMs: options.requestTimeoutMs,
83
+ initializationTimeoutMs: options.initializationTimeoutMs,
84
+ context: options.context
85
+ });
86
+ try {
87
+ return client.get(options.name, { context: options.context });
88
+ } finally {
89
+ client.close();
90
+ }
91
+ }
92
+
93
+ //#endregion
94
+ exports.getConfig = getConfig;
95
+ exports.getReplaneSnapshot = getReplaneSnapshot;
@@ -0,0 +1,114 @@
1
+ import { ReplaneClientOptions, ReplaneContext, ReplaneSnapshot } from "@replanejs/sdk";
2
+
3
+ //#region src/server.d.ts
4
+
5
+ interface GetReplaneSnapshotOptions<T extends object> {
6
+ /**
7
+ * Base URL of the Replane instance (no trailing slash).
8
+ */
9
+ baseUrl: string;
10
+ /**
11
+ * Project SDK key for authorization.
12
+ */
13
+ sdkKey: string;
14
+ /**
15
+ * Custom fetch implementation (useful for caching configuration).
16
+ * In Next.js, you can use the fetch options for caching:
17
+ * ```ts
18
+ * fetchFn: (url, init) => fetch(url, { ...init, next: { revalidate: 60 } })
19
+ * ```
20
+ */
21
+ fetchFn?: typeof fetch;
22
+ /**
23
+ * Optional timeout in ms for the request.
24
+ * @default 2000
25
+ */
26
+ requestTimeoutMs?: number;
27
+ /**
28
+ * Optional timeout in ms for initialization.
29
+ * @default 5000
30
+ */
31
+ initializationTimeoutMs?: number;
32
+ /**
33
+ * Default context used for override evaluation.
34
+ * This context will be included in the snapshot.
35
+ */
36
+ context?: ReplaneContext;
37
+ /**
38
+ * Config names that must be present before the client is ready.
39
+ */
40
+ required?: ReplaneClientOptions<T>["required"];
41
+ /**
42
+ * Fallback values to use if configs are not available.
43
+ */
44
+ fallbacks?: ReplaneClientOptions<T>["fallbacks"];
45
+ }
46
+ /**
47
+ * Fetch configs from Replane and return a serializable snapshot.
48
+ *
49
+ * This is the primary server-side function for Next.js integration.
50
+ * It creates a Replane client, waits for initialization, captures a snapshot,
51
+ * and closes the client.
52
+ *
53
+ * The snapshot can be passed to `ReplaneNextProvider` for client-side hydration.
54
+ *
55
+ * @example
56
+ * ```tsx
57
+ * // In a Server Component
58
+ * const snapshot = await getReplaneSnapshot({
59
+ * baseUrl: process.env.REPLANE_BASE_URL!,
60
+ * sdkKey: process.env.REPLANE_SDK_KEY!,
61
+ * context: { userId: user.id },
62
+ * });
63
+ * ```
64
+ *
65
+ * @example
66
+ * ```tsx
67
+ * // With Next.js caching
68
+ * const snapshot = await getReplaneSnapshot({
69
+ * baseUrl: process.env.REPLANE_BASE_URL!,
70
+ * sdkKey: process.env.REPLANE_SDK_KEY!,
71
+ * fetchFn: (url, init) => fetch(url, {
72
+ * ...init,
73
+ * next: { revalidate: 60 }, // Revalidate every 60 seconds
74
+ * }),
75
+ * });
76
+ * ```
77
+ */
78
+ declare function getReplaneSnapshot<T extends object = Record<string, unknown>>(options: GetReplaneSnapshotOptions<T>): Promise<ReplaneSnapshot<T>>;
79
+ /**
80
+ * Get a config value directly on the server.
81
+ *
82
+ * This is useful when you need a single config value in a Server Component
83
+ * or server-side code and don't need the full snapshot/hydration flow.
84
+ *
85
+ * Note: This creates a new client for each call, so prefer `getReplaneSnapshot`
86
+ * if you need multiple configs or client-side hydration.
87
+ *
88
+ * @example
89
+ * ```tsx
90
+ * // In a Server Component
91
+ * const maintenanceMode = await getConfig<boolean>({
92
+ * name: "maintenance-mode",
93
+ * baseUrl: process.env.REPLANE_BASE_URL!,
94
+ * sdkKey: process.env.REPLANE_SDK_KEY!,
95
+ * });
96
+ *
97
+ * if (maintenanceMode) {
98
+ * return <MaintenancePage />;
99
+ * }
100
+ * ```
101
+ */
102
+ declare function getConfig<T>(options: {
103
+ name: string;
104
+ baseUrl: string;
105
+ sdkKey: string;
106
+ fetchFn?: typeof fetch;
107
+ requestTimeoutMs?: number;
108
+ initializationTimeoutMs?: number;
109
+ context?: ReplaneContext;
110
+ }): Promise<T>;
111
+ //# sourceMappingURL=server.d.ts.map
112
+ //#endregion
113
+ export { GetReplaneSnapshotOptions, type ReplaneContext, type ReplaneSnapshot, getConfig, getReplaneSnapshot };
114
+ //# sourceMappingURL=server.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.cts","names":[],"sources":["../src/server.ts"],"sourcesContent":[],"mappings":";;;;UAiDiB;;;;;;;;;;;;;;;;mBAkBE;;;;;;;;;;;;;;;YAkBP;;;;aAKC,qBAAqB;;;;cAKpB,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAmCb,sCAAsC,kCACjD,0BAA0B,KAClC,QAAQ,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;iBA0CL;;;;mBAIH;;;YAGP;IACR,QAAQ"}
@@ -0,0 +1,114 @@
1
+ import { ReplaneClientOptions, ReplaneContext, ReplaneSnapshot } from "@replanejs/sdk";
2
+
3
+ //#region src/server.d.ts
4
+
5
+ interface GetReplaneSnapshotOptions<T extends object> {
6
+ /**
7
+ * Base URL of the Replane instance (no trailing slash).
8
+ */
9
+ baseUrl: string;
10
+ /**
11
+ * Project SDK key for authorization.
12
+ */
13
+ sdkKey: string;
14
+ /**
15
+ * Custom fetch implementation (useful for caching configuration).
16
+ * In Next.js, you can use the fetch options for caching:
17
+ * ```ts
18
+ * fetchFn: (url, init) => fetch(url, { ...init, next: { revalidate: 60 } })
19
+ * ```
20
+ */
21
+ fetchFn?: typeof fetch;
22
+ /**
23
+ * Optional timeout in ms for the request.
24
+ * @default 2000
25
+ */
26
+ requestTimeoutMs?: number;
27
+ /**
28
+ * Optional timeout in ms for initialization.
29
+ * @default 5000
30
+ */
31
+ initializationTimeoutMs?: number;
32
+ /**
33
+ * Default context used for override evaluation.
34
+ * This context will be included in the snapshot.
35
+ */
36
+ context?: ReplaneContext;
37
+ /**
38
+ * Config names that must be present before the client is ready.
39
+ */
40
+ required?: ReplaneClientOptions<T>["required"];
41
+ /**
42
+ * Fallback values to use if configs are not available.
43
+ */
44
+ fallbacks?: ReplaneClientOptions<T>["fallbacks"];
45
+ }
46
+ /**
47
+ * Fetch configs from Replane and return a serializable snapshot.
48
+ *
49
+ * This is the primary server-side function for Next.js integration.
50
+ * It creates a Replane client, waits for initialization, captures a snapshot,
51
+ * and closes the client.
52
+ *
53
+ * The snapshot can be passed to `ReplaneNextProvider` for client-side hydration.
54
+ *
55
+ * @example
56
+ * ```tsx
57
+ * // In a Server Component
58
+ * const snapshot = await getReplaneSnapshot({
59
+ * baseUrl: process.env.REPLANE_BASE_URL!,
60
+ * sdkKey: process.env.REPLANE_SDK_KEY!,
61
+ * context: { userId: user.id },
62
+ * });
63
+ * ```
64
+ *
65
+ * @example
66
+ * ```tsx
67
+ * // With Next.js caching
68
+ * const snapshot = await getReplaneSnapshot({
69
+ * baseUrl: process.env.REPLANE_BASE_URL!,
70
+ * sdkKey: process.env.REPLANE_SDK_KEY!,
71
+ * fetchFn: (url, init) => fetch(url, {
72
+ * ...init,
73
+ * next: { revalidate: 60 }, // Revalidate every 60 seconds
74
+ * }),
75
+ * });
76
+ * ```
77
+ */
78
+ declare function getReplaneSnapshot<T extends object = Record<string, unknown>>(options: GetReplaneSnapshotOptions<T>): Promise<ReplaneSnapshot<T>>;
79
+ /**
80
+ * Get a config value directly on the server.
81
+ *
82
+ * This is useful when you need a single config value in a Server Component
83
+ * or server-side code and don't need the full snapshot/hydration flow.
84
+ *
85
+ * Note: This creates a new client for each call, so prefer `getReplaneSnapshot`
86
+ * if you need multiple configs or client-side hydration.
87
+ *
88
+ * @example
89
+ * ```tsx
90
+ * // In a Server Component
91
+ * const maintenanceMode = await getConfig<boolean>({
92
+ * name: "maintenance-mode",
93
+ * baseUrl: process.env.REPLANE_BASE_URL!,
94
+ * sdkKey: process.env.REPLANE_SDK_KEY!,
95
+ * });
96
+ *
97
+ * if (maintenanceMode) {
98
+ * return <MaintenancePage />;
99
+ * }
100
+ * ```
101
+ */
102
+ declare function getConfig<T>(options: {
103
+ name: string;
104
+ baseUrl: string;
105
+ sdkKey: string;
106
+ fetchFn?: typeof fetch;
107
+ requestTimeoutMs?: number;
108
+ initializationTimeoutMs?: number;
109
+ context?: ReplaneContext;
110
+ }): Promise<T>;
111
+ //# sourceMappingURL=server.d.ts.map
112
+ //#endregion
113
+ export { GetReplaneSnapshotOptions, type ReplaneContext, type ReplaneSnapshot, getConfig, getReplaneSnapshot };
114
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","names":[],"sources":["../src/server.ts"],"sourcesContent":[],"mappings":";;;;UAiDiB;;;;;;;;;;;;;;;;mBAkBE;;;;;;;;;;;;;;;YAkBP;;;;aAKC,qBAAqB;;;;cAKpB,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAmCb,sCAAsC,kCACjD,0BAA0B,KAClC,QAAQ,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;iBA0CL;;;;mBAIH;;;YAGP;IACR,QAAQ"}
package/dist/server.js ADDED
@@ -0,0 +1,94 @@
1
+ import { createReplaneClient } from "@replanejs/sdk";
2
+
3
+ //#region src/server.ts
4
+ /**
5
+ * Fetch configs from Replane and return a serializable snapshot.
6
+ *
7
+ * This is the primary server-side function for Next.js integration.
8
+ * It creates a Replane client, waits for initialization, captures a snapshot,
9
+ * and closes the client.
10
+ *
11
+ * The snapshot can be passed to `ReplaneNextProvider` for client-side hydration.
12
+ *
13
+ * @example
14
+ * ```tsx
15
+ * // In a Server Component
16
+ * const snapshot = await getReplaneSnapshot({
17
+ * baseUrl: process.env.REPLANE_BASE_URL!,
18
+ * sdkKey: process.env.REPLANE_SDK_KEY!,
19
+ * context: { userId: user.id },
20
+ * });
21
+ * ```
22
+ *
23
+ * @example
24
+ * ```tsx
25
+ * // With Next.js caching
26
+ * const snapshot = await getReplaneSnapshot({
27
+ * baseUrl: process.env.REPLANE_BASE_URL!,
28
+ * sdkKey: process.env.REPLANE_SDK_KEY!,
29
+ * fetchFn: (url, init) => fetch(url, {
30
+ * ...init,
31
+ * next: { revalidate: 60 }, // Revalidate every 60 seconds
32
+ * }),
33
+ * });
34
+ * ```
35
+ */
36
+ async function getReplaneSnapshot(options) {
37
+ const client = await createReplaneClient({
38
+ baseUrl: options.baseUrl,
39
+ sdkKey: options.sdkKey,
40
+ fetchFn: options.fetchFn,
41
+ requestTimeoutMs: options.requestTimeoutMs,
42
+ initializationTimeoutMs: options.initializationTimeoutMs,
43
+ context: options.context,
44
+ required: options.required,
45
+ fallbacks: options.fallbacks
46
+ });
47
+ try {
48
+ return client.getSnapshot();
49
+ } finally {
50
+ client.close();
51
+ }
52
+ }
53
+ /**
54
+ * Get a config value directly on the server.
55
+ *
56
+ * This is useful when you need a single config value in a Server Component
57
+ * or server-side code and don't need the full snapshot/hydration flow.
58
+ *
59
+ * Note: This creates a new client for each call, so prefer `getReplaneSnapshot`
60
+ * if you need multiple configs or client-side hydration.
61
+ *
62
+ * @example
63
+ * ```tsx
64
+ * // In a Server Component
65
+ * const maintenanceMode = await getConfig<boolean>({
66
+ * name: "maintenance-mode",
67
+ * baseUrl: process.env.REPLANE_BASE_URL!,
68
+ * sdkKey: process.env.REPLANE_SDK_KEY!,
69
+ * });
70
+ *
71
+ * if (maintenanceMode) {
72
+ * return <MaintenancePage />;
73
+ * }
74
+ * ```
75
+ */
76
+ async function getConfig(options) {
77
+ const client = await createReplaneClient({
78
+ baseUrl: options.baseUrl,
79
+ sdkKey: options.sdkKey,
80
+ fetchFn: options.fetchFn,
81
+ requestTimeoutMs: options.requestTimeoutMs,
82
+ initializationTimeoutMs: options.initializationTimeoutMs,
83
+ context: options.context
84
+ });
85
+ try {
86
+ return client.get(options.name, { context: options.context });
87
+ } finally {
88
+ client.close();
89
+ }
90
+ }
91
+
92
+ //#endregion
93
+ export { getConfig, getReplaneSnapshot };
94
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","names":["options: GetReplaneSnapshotOptions<T>","options: {\n name: string;\n baseUrl: string;\n sdkKey: string;\n fetchFn?: typeof fetch;\n requestTimeoutMs?: number;\n initializationTimeoutMs?: number;\n context?: ReplaneContext;\n}"],"sources":["../src/server.ts"],"sourcesContent":["/**\n * Server-side utilities for Replane in Next.js.\n *\n * These functions are designed to be used in:\n * - React Server Components (RSC)\n * - getServerSideProps\n * - API routes\n * - Server Actions\n *\n * @example\n * ```tsx\n * // app/layout.tsx (Server Component)\n * import { getReplaneSnapshot } from \"@replanejs/next/server\";\n * import { ReplaneNextProvider } from \"@replanejs/next\";\n *\n * export default async function RootLayout({ children }) {\n * const snapshot = await getReplaneSnapshot({\n * baseUrl: process.env.REPLANE_BASE_URL!,\n * sdkKey: process.env.REPLANE_SDK_KEY!,\n * });\n *\n * return (\n * <html>\n * <body>\n * <ReplaneNextProvider\n * snapshot={snapshot}\n * connection={{\n * baseUrl: process.env.NEXT_PUBLIC_REPLANE_BASE_URL!,\n * sdkKey: process.env.NEXT_PUBLIC_REPLANE_SDK_KEY!,\n * }}\n * >\n * {children}\n * </ReplaneNextProvider>\n * </body>\n * </html>\n * );\n * }\n * ```\n */\n\nimport {\n createReplaneClient,\n type ReplaneClientOptions,\n type ReplaneSnapshot,\n type ReplaneContext,\n} from \"@replanejs/sdk\";\n\nexport type { ReplaneSnapshot, ReplaneContext };\n\nexport interface GetReplaneSnapshotOptions<T extends object> {\n /**\n * Base URL of the Replane instance (no trailing slash).\n */\n baseUrl: string;\n\n /**\n * Project SDK key for authorization.\n */\n sdkKey: string;\n\n /**\n * Custom fetch implementation (useful for caching configuration).\n * In Next.js, you can use the fetch options for caching:\n * ```ts\n * fetchFn: (url, init) => fetch(url, { ...init, next: { revalidate: 60 } })\n * ```\n */\n fetchFn?: typeof fetch;\n\n /**\n * Optional timeout in ms for the request.\n * @default 2000\n */\n requestTimeoutMs?: number;\n\n /**\n * Optional timeout in ms for initialization.\n * @default 5000\n */\n initializationTimeoutMs?: number;\n\n /**\n * Default context used for override evaluation.\n * This context will be included in the snapshot.\n */\n context?: ReplaneContext;\n\n /**\n * Config names that must be present before the client is ready.\n */\n required?: ReplaneClientOptions<T>[\"required\"];\n\n /**\n * Fallback values to use if configs are not available.\n */\n fallbacks?: ReplaneClientOptions<T>[\"fallbacks\"];\n}\n\n/**\n * Fetch configs from Replane and return a serializable snapshot.\n *\n * This is the primary server-side function for Next.js integration.\n * It creates a Replane client, waits for initialization, captures a snapshot,\n * and closes the client.\n *\n * The snapshot can be passed to `ReplaneNextProvider` for client-side hydration.\n *\n * @example\n * ```tsx\n * // In a Server Component\n * const snapshot = await getReplaneSnapshot({\n * baseUrl: process.env.REPLANE_BASE_URL!,\n * sdkKey: process.env.REPLANE_SDK_KEY!,\n * context: { userId: user.id },\n * });\n * ```\n *\n * @example\n * ```tsx\n * // With Next.js caching\n * const snapshot = await getReplaneSnapshot({\n * baseUrl: process.env.REPLANE_BASE_URL!,\n * sdkKey: process.env.REPLANE_SDK_KEY!,\n * fetchFn: (url, init) => fetch(url, {\n * ...init,\n * next: { revalidate: 60 }, // Revalidate every 60 seconds\n * }),\n * });\n * ```\n */\nexport async function getReplaneSnapshot<T extends object = Record<string, unknown>>(\n options: GetReplaneSnapshotOptions<T>\n): Promise<ReplaneSnapshot<T>> {\n const client = await createReplaneClient<T>({\n baseUrl: options.baseUrl,\n sdkKey: options.sdkKey,\n fetchFn: options.fetchFn,\n requestTimeoutMs: options.requestTimeoutMs,\n initializationTimeoutMs: options.initializationTimeoutMs,\n context: options.context,\n required: options.required,\n fallbacks: options.fallbacks,\n });\n\n try {\n return client.getSnapshot();\n } finally {\n client.close();\n }\n}\n\n/**\n * Get a config value directly on the server.\n *\n * This is useful when you need a single config value in a Server Component\n * or server-side code and don't need the full snapshot/hydration flow.\n *\n * Note: This creates a new client for each call, so prefer `getReplaneSnapshot`\n * if you need multiple configs or client-side hydration.\n *\n * @example\n * ```tsx\n * // In a Server Component\n * const maintenanceMode = await getConfig<boolean>({\n * name: \"maintenance-mode\",\n * baseUrl: process.env.REPLANE_BASE_URL!,\n * sdkKey: process.env.REPLANE_SDK_KEY!,\n * });\n *\n * if (maintenanceMode) {\n * return <MaintenancePage />;\n * }\n * ```\n */\nexport async function getConfig<T>(options: {\n name: string;\n baseUrl: string;\n sdkKey: string;\n fetchFn?: typeof fetch;\n requestTimeoutMs?: number;\n initializationTimeoutMs?: number;\n context?: ReplaneContext;\n}): Promise<T> {\n const client = await createReplaneClient({\n baseUrl: options.baseUrl,\n sdkKey: options.sdkKey,\n fetchFn: options.fetchFn,\n requestTimeoutMs: options.requestTimeoutMs,\n initializationTimeoutMs: options.initializationTimeoutMs,\n context: options.context,\n });\n\n try {\n return client.get(options.name, { context: options.context }) as T;\n } finally {\n client.close();\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkIA,eAAsB,mBACpBA,SAC6B;CAC7B,MAAM,SAAS,MAAM,oBAAuB;EAC1C,SAAS,QAAQ;EACjB,QAAQ,QAAQ;EAChB,SAAS,QAAQ;EACjB,kBAAkB,QAAQ;EAC1B,yBAAyB,QAAQ;EACjC,SAAS,QAAQ;EACjB,UAAU,QAAQ;EAClB,WAAW,QAAQ;CACpB,EAAC;AAEF,KAAI;AACF,SAAO,OAAO,aAAa;CAC5B,UAAS;AACR,SAAO,OAAO;CACf;AACF;;;;;;;;;;;;;;;;;;;;;;;;AAyBD,eAAsB,UAAaC,SAQpB;CACb,MAAM,SAAS,MAAM,oBAAoB;EACvC,SAAS,QAAQ;EACjB,QAAQ,QAAQ;EAChB,SAAS,QAAQ;EACjB,kBAAkB,QAAQ;EAC1B,yBAAyB,QAAQ;EACjC,SAAS,QAAQ;CAClB,EAAC;AAEF,KAAI;AACF,SAAO,OAAO,IAAI,QAAQ,MAAM,EAAE,SAAS,QAAQ,QAAS,EAAC;CAC9D,UAAS;AACR,SAAO,OAAO;CACf;AACF"}