frappe-nextjs 0.1.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.
Files changed (98) hide show
  1. package/README.md +90 -0
  2. package/dist/bin/cli.d.ts +3 -0
  3. package/dist/bin/cli.d.ts.map +1 -0
  4. package/dist/bin/cli.js +156 -0
  5. package/dist/bin/cli.js.map +1 -0
  6. package/dist/build/boilerplates.d.ts +12 -0
  7. package/dist/build/boilerplates.d.ts.map +1 -0
  8. package/dist/build/boilerplates.js +261 -0
  9. package/dist/build/boilerplates.js.map +1 -0
  10. package/dist/build/build.d.ts +27 -0
  11. package/dist/build/build.d.ts.map +1 -0
  12. package/dist/build/build.js +172 -0
  13. package/dist/build/build.js.map +1 -0
  14. package/dist/build/context-generator.d.ts +13 -0
  15. package/dist/build/context-generator.d.ts.map +1 -0
  16. package/dist/build/context-generator.js +76 -0
  17. package/dist/build/context-generator.js.map +1 -0
  18. package/dist/build/hooks-patcher.d.ts +11 -0
  19. package/dist/build/hooks-patcher.d.ts.map +1 -0
  20. package/dist/build/hooks-patcher.js +78 -0
  21. package/dist/build/hooks-patcher.js.map +1 -0
  22. package/dist/build/index.d.ts +8 -0
  23. package/dist/build/index.d.ts.map +1 -0
  24. package/dist/build/index.js +33 -0
  25. package/dist/build/index.js.map +1 -0
  26. package/dist/build/init.d.ts +27 -0
  27. package/dist/build/init.d.ts.map +1 -0
  28. package/dist/build/init.js +175 -0
  29. package/dist/build/init.js.map +1 -0
  30. package/dist/build/nginx-generator.d.ts +22 -0
  31. package/dist/build/nginx-generator.d.ts.map +1 -0
  32. package/dist/build/nginx-generator.js +114 -0
  33. package/dist/build/nginx-generator.js.map +1 -0
  34. package/dist/build/supervisor-generator.d.ts +31 -0
  35. package/dist/build/supervisor-generator.d.ts.map +1 -0
  36. package/dist/build/supervisor-generator.js +105 -0
  37. package/dist/build/supervisor-generator.js.map +1 -0
  38. package/dist/client/FrappeClient.d.ts +143 -0
  39. package/dist/client/FrappeClient.d.ts.map +1 -0
  40. package/dist/client/FrappeClient.js +446 -0
  41. package/dist/client/FrappeClient.js.map +1 -0
  42. package/dist/client/index.d.ts +3 -0
  43. package/dist/client/index.d.ts.map +1 -0
  44. package/dist/client/index.js +21 -0
  45. package/dist/client/index.js.map +1 -0
  46. package/dist/client/types.d.ts +140 -0
  47. package/dist/client/types.d.ts.map +1 -0
  48. package/dist/client/types.js +17 -0
  49. package/dist/client/types.js.map +1 -0
  50. package/dist/hooks/FrappeProvider.d.ts +41 -0
  51. package/dist/hooks/FrappeProvider.d.ts.map +1 -0
  52. package/dist/hooks/FrappeProvider.js +48 -0
  53. package/dist/hooks/FrappeProvider.js.map +1 -0
  54. package/dist/hooks/index.d.ts +8 -0
  55. package/dist/hooks/index.d.ts.map +1 -0
  56. package/dist/hooks/index.js +17 -0
  57. package/dist/hooks/index.js.map +1 -0
  58. package/dist/hooks/useFrappeAuth.d.ts +37 -0
  59. package/dist/hooks/useFrappeAuth.d.ts.map +1 -0
  60. package/dist/hooks/useFrappeAuth.js +111 -0
  61. package/dist/hooks/useFrappeAuth.js.map +1 -0
  62. package/dist/hooks/useFrappeCall.d.ts +26 -0
  63. package/dist/hooks/useFrappeCall.d.ts.map +1 -0
  64. package/dist/hooks/useFrappeCall.js +47 -0
  65. package/dist/hooks/useFrappeCall.js.map +1 -0
  66. package/dist/hooks/useFrappeDoc.d.ts +37 -0
  67. package/dist/hooks/useFrappeDoc.d.ts.map +1 -0
  68. package/dist/hooks/useFrappeDoc.js +79 -0
  69. package/dist/hooks/useFrappeDoc.js.map +1 -0
  70. package/dist/hooks/useFrappeDocList.d.ts +37 -0
  71. package/dist/hooks/useFrappeDocList.d.ts.map +1 -0
  72. package/dist/hooks/useFrappeDocList.js +65 -0
  73. package/dist/hooks/useFrappeDocList.js.map +1 -0
  74. package/dist/hooks/useFrappeFileUpload.d.ts +40 -0
  75. package/dist/hooks/useFrappeFileUpload.d.ts.map +1 -0
  76. package/dist/hooks/useFrappeFileUpload.js +68 -0
  77. package/dist/hooks/useFrappeFileUpload.js.map +1 -0
  78. package/dist/index.d.ts +10 -0
  79. package/dist/index.d.ts.map +1 -0
  80. package/dist/index.js +24 -0
  81. package/dist/index.js.map +1 -0
  82. package/dist/ssr/index.d.ts +4 -0
  83. package/dist/ssr/index.d.ts.map +1 -0
  84. package/dist/ssr/index.js +13 -0
  85. package/dist/ssr/index.js.map +1 -0
  86. package/dist/ssr/middleware.d.ts +18 -0
  87. package/dist/ssr/middleware.d.ts.map +1 -0
  88. package/dist/ssr/middleware.js +132 -0
  89. package/dist/ssr/middleware.js.map +1 -0
  90. package/dist/ssr/proxy-config.d.ts +33 -0
  91. package/dist/ssr/proxy-config.d.ts.map +1 -0
  92. package/dist/ssr/proxy-config.js +133 -0
  93. package/dist/ssr/proxy-config.js.map +1 -0
  94. package/dist/ssr/server-client.d.ts +73 -0
  95. package/dist/ssr/server-client.d.ts.map +1 -0
  96. package/dist/ssr/server-client.js +94 -0
  97. package/dist/ssr/server-client.js.map +1 -0
  98. package/package.json +79 -0
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ 'use client';
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.useFrappeFileUpload = useFrappeFileUpload;
5
+ const react_1 = require("react");
6
+ const FrappeProvider_1 = require("./FrappeProvider");
7
+ /**
8
+ * Hook to upload files to Frappe with progress tracking.
9
+ *
10
+ * @example
11
+ * ```tsx
12
+ * function FileUploader({ doctype, docname }: { doctype: string; docname: string }) {
13
+ * const { upload, isUploading, progress, result, error, reset } = useFrappeFileUpload();
14
+ *
15
+ * const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
16
+ * const file = e.target.files?.[0];
17
+ * if (file) {
18
+ * upload({ file, doctype, docname, isPrivate: true });
19
+ * }
20
+ * };
21
+ *
22
+ * return (
23
+ * <div>
24
+ * <input type="file" onChange={handleChange} disabled={isUploading} />
25
+ * {isUploading && <progress value={progress} max={100} />}
26
+ * {result && <a href={result.file_url}>Uploaded: {result.file_name}</a>}
27
+ * {error && <p>Error: {error.message}</p>}
28
+ * </div>
29
+ * );
30
+ * }
31
+ * ```
32
+ */
33
+ function useFrappeFileUpload() {
34
+ const client = (0, FrappeProvider_1.useFrappeClient)();
35
+ const [state, setState] = (0, react_1.useState)({
36
+ isUploading: false,
37
+ progress: 0,
38
+ error: null,
39
+ result: null,
40
+ });
41
+ const upload = (0, react_1.useCallback)(async (options) => {
42
+ setState({ isUploading: true, progress: 0, error: null, result: null });
43
+ try {
44
+ const result = await client.uploadFile({
45
+ ...options,
46
+ onProgress: (progress) => {
47
+ setState((prev) => ({ ...prev, progress }));
48
+ },
49
+ });
50
+ setState({ isUploading: false, progress: 100, error: null, result });
51
+ return result;
52
+ }
53
+ catch (err) {
54
+ const error = err;
55
+ setState((prev) => ({ ...prev, isUploading: false, error }));
56
+ throw error;
57
+ }
58
+ }, [client]);
59
+ const reset = (0, react_1.useCallback)(() => {
60
+ setState({ isUploading: false, progress: 0, error: null, result: null });
61
+ }, []);
62
+ return {
63
+ upload,
64
+ reset,
65
+ ...state,
66
+ };
67
+ }
68
+ //# sourceMappingURL=useFrappeFileUpload.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useFrappeFileUpload.js","sourceRoot":"","sources":["../../src/hooks/useFrappeFileUpload.ts"],"names":[],"mappings":";AAAA,YAAY,CAAC;;AA2Cb,kDA0CC;AAnFD,iCAA8C;AAC9C,qDAAmD;AAcnD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,SAAgB,mBAAmB;IACjC,MAAM,MAAM,GAAG,IAAA,gCAAe,GAAE,CAAC;IAEjC,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,IAAA,gBAAQ,EAAc;QAC9C,WAAW,EAAE,KAAK;QAClB,QAAQ,EAAE,CAAC;QACX,KAAK,EAAE,IAAI;QACX,MAAM,EAAE,IAAI;KACb,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,IAAA,mBAAW,EACxB,KAAK,EAAE,OAA8C,EAAE,EAAE;QACvD,QAAQ,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QAExE,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC;gBACrC,GAAG,OAAO;gBACV,UAAU,EAAE,CAAC,QAAQ,EAAE,EAAE;oBACvB,QAAQ,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;gBAC9C,CAAC;aACF,CAAC,CAAC;YAEH,QAAQ,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;YACrE,OAAO,MAAM,CAAC;QAChB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,KAAK,GAAG,GAAY,CAAC;YAC3B,QAAQ,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;YAC7D,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC,EACD,CAAC,MAAM,CAAC,CACT,CAAC;IAEF,MAAM,KAAK,GAAG,IAAA,mBAAW,EAAC,GAAG,EAAE;QAC7B,QAAQ,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3E,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO;QACL,MAAM;QACN,KAAK;QACL,GAAG,KAAK;KACT,CAAC;AACJ,CAAC"}
@@ -0,0 +1,10 @@
1
+ export { FrappeClient } from './client/FrappeClient';
2
+ export type { FrappeClientConfig, FrappeDoc, FrappeDocBase, FrappeResponse, FrappeApiError, Filter, FilterOperator, OrderBy, GetDocListParams, GetDocParams, CreateDocParams, UpdateDocParams, CallParams, FileUploadOptions, FileUploadResponse, AuthState, LoginCredentials, } from './client/types';
3
+ export { FrappeProvider, useFrappeClient, } from './hooks/FrappeProvider';
4
+ export type { FrappeProviderProps } from './hooks/FrappeProvider';
5
+ export { useFrappeCall } from './hooks/useFrappeCall';
6
+ export { useFrappeDocList } from './hooks/useFrappeDocList';
7
+ export { useFrappeDoc } from './hooks/useFrappeDoc';
8
+ export { useFrappeAuth } from './hooks/useFrappeAuth';
9
+ export { useFrappeFileUpload } from './hooks/useFrappeFileUpload';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,YAAY,EACV,kBAAkB,EAClB,SAAS,EACT,aAAa,EACb,cAAc,EACd,cAAc,EACd,MAAM,EACN,cAAc,EACd,OAAO,EACP,gBAAgB,EAChB,YAAY,EACZ,eAAe,EACf,eAAe,EACf,UAAU,EACV,iBAAiB,EACjB,kBAAkB,EAClB,SAAS,EACT,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACL,cAAc,EACd,eAAe,GAChB,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ // ─── Main exports for frappe-nextjs ────────────────────────────────
3
+ // NOTE: This is the client-safe entry point. Do NOT import server-only
4
+ // modules here (fs, path, etc). Server utilities live in 'frappe-nextjs/ssr'.
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.useFrappeFileUpload = exports.useFrappeAuth = exports.useFrappeDoc = exports.useFrappeDocList = exports.useFrappeCall = exports.useFrappeClient = exports.FrappeProvider = exports.FrappeClient = void 0;
7
+ // Client
8
+ var FrappeClient_1 = require("./client/FrappeClient");
9
+ Object.defineProperty(exports, "FrappeClient", { enumerable: true, get: function () { return FrappeClient_1.FrappeClient; } });
10
+ // Hooks
11
+ var FrappeProvider_1 = require("./hooks/FrappeProvider");
12
+ Object.defineProperty(exports, "FrappeProvider", { enumerable: true, get: function () { return FrappeProvider_1.FrappeProvider; } });
13
+ Object.defineProperty(exports, "useFrappeClient", { enumerable: true, get: function () { return FrappeProvider_1.useFrappeClient; } });
14
+ var useFrappeCall_1 = require("./hooks/useFrappeCall");
15
+ Object.defineProperty(exports, "useFrappeCall", { enumerable: true, get: function () { return useFrappeCall_1.useFrappeCall; } });
16
+ var useFrappeDocList_1 = require("./hooks/useFrappeDocList");
17
+ Object.defineProperty(exports, "useFrappeDocList", { enumerable: true, get: function () { return useFrappeDocList_1.useFrappeDocList; } });
18
+ var useFrappeDoc_1 = require("./hooks/useFrappeDoc");
19
+ Object.defineProperty(exports, "useFrappeDoc", { enumerable: true, get: function () { return useFrappeDoc_1.useFrappeDoc; } });
20
+ var useFrappeAuth_1 = require("./hooks/useFrappeAuth");
21
+ Object.defineProperty(exports, "useFrappeAuth", { enumerable: true, get: function () { return useFrappeAuth_1.useFrappeAuth; } });
22
+ var useFrappeFileUpload_1 = require("./hooks/useFrappeFileUpload");
23
+ Object.defineProperty(exports, "useFrappeFileUpload", { enumerable: true, get: function () { return useFrappeFileUpload_1.useFrappeFileUpload; } });
24
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,sEAAsE;AACtE,uEAAuE;AACvE,8EAA8E;;;AAE9E,SAAS;AACT,sDAAqD;AAA5C,4GAAA,YAAY,OAAA;AAqBrB,QAAQ;AACR,yDAGgC;AAF9B,gHAAA,cAAc,OAAA;AACd,iHAAA,eAAe,OAAA;AAGjB,uDAAsD;AAA7C,8GAAA,aAAa,OAAA;AACtB,6DAA4D;AAAnD,oHAAA,gBAAgB,OAAA;AACzB,qDAAoD;AAA3C,4GAAA,YAAY,OAAA;AACrB,uDAAsD;AAA7C,8GAAA,aAAa,OAAA;AACtB,mEAAkE;AAAzD,0HAAA,mBAAmB,OAAA"}
@@ -0,0 +1,4 @@
1
+ export { createServerClient, createRequestClient } from './server-client';
2
+ export { generateRewrites, generateNextConfig } from './proxy-config';
3
+ export { generateProxy, generateMiddleware } from './middleware';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ssr/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAC1E,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACtE,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateMiddleware = exports.generateProxy = exports.generateNextConfig = exports.generateRewrites = exports.createRequestClient = exports.createServerClient = void 0;
4
+ var server_client_1 = require("./server-client");
5
+ Object.defineProperty(exports, "createServerClient", { enumerable: true, get: function () { return server_client_1.createServerClient; } });
6
+ Object.defineProperty(exports, "createRequestClient", { enumerable: true, get: function () { return server_client_1.createRequestClient; } });
7
+ var proxy_config_1 = require("./proxy-config");
8
+ Object.defineProperty(exports, "generateRewrites", { enumerable: true, get: function () { return proxy_config_1.generateRewrites; } });
9
+ Object.defineProperty(exports, "generateNextConfig", { enumerable: true, get: function () { return proxy_config_1.generateNextConfig; } });
10
+ var middleware_1 = require("./middleware");
11
+ Object.defineProperty(exports, "generateProxy", { enumerable: true, get: function () { return middleware_1.generateProxy; } });
12
+ Object.defineProperty(exports, "generateMiddleware", { enumerable: true, get: function () { return middleware_1.generateMiddleware; } });
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ssr/index.ts"],"names":[],"mappings":";;;AAAA,iDAA0E;AAAjE,mHAAA,kBAAkB,OAAA;AAAE,oHAAA,mBAAmB,OAAA;AAChD,+CAAsE;AAA7D,gHAAA,gBAAgB,OAAA;AAAE,kHAAA,kBAAkB,OAAA;AAC7C,2CAAiE;AAAxD,2GAAA,aAAa,OAAA;AAAE,gHAAA,kBAAkB,OAAA"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Generates Next.js 16+ proxy.ts code for Frappe integration.
3
+ *
4
+ * In Next.js 16, `middleware.ts` has been renamed to `proxy.ts`.
5
+ * The proxy intercepts requests to protected routes and checks
6
+ * if the user has valid Frappe session cookies. It also handles
7
+ * proxying API requests to the Frappe backend.
8
+ *
9
+ * For Next.js 14/15, use `generateMiddleware()` instead.
10
+ */
11
+ export declare function generateProxy(spaName: string, frappePort?: number): string;
12
+ /**
13
+ * Generates Next.js 14/15 middleware.ts code (legacy, still works in Next.js 16).
14
+ *
15
+ * For Next.js 16+, prefer `generateProxy()` which uses the new proxy.ts convention.
16
+ */
17
+ export declare function generateMiddleware(spaName: string): string;
18
+ //# sourceMappingURL=middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/ssr/middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,GAAE,MAAa,GAAG,MAAM,CAoEhF;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CA0C1D"}
@@ -0,0 +1,132 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateProxy = generateProxy;
4
+ exports.generateMiddleware = generateMiddleware;
5
+ /**
6
+ * Generates Next.js 16+ proxy.ts code for Frappe integration.
7
+ *
8
+ * In Next.js 16, `middleware.ts` has been renamed to `proxy.ts`.
9
+ * The proxy intercepts requests to protected routes and checks
10
+ * if the user has valid Frappe session cookies. It also handles
11
+ * proxying API requests to the Frappe backend.
12
+ *
13
+ * For Next.js 14/15, use `generateMiddleware()` instead.
14
+ */
15
+ function generateProxy(spaName, frappePort = 8000) {
16
+ return `import { NextResponse } from 'next/server';
17
+ import type { NextRequest } from 'next/server';
18
+
19
+ /**
20
+ * Proxy to handle Frappe API proxying and authentication for Next.js 16+ routes.
21
+ *
22
+ * - Proxies /api/*, /assets/*, /files/* to the Frappe backend
23
+ * - Checks for 'user_id' cookie set by Frappe
24
+ * - Redirects unauthenticated users to Frappe login
25
+ */
26
+ export function proxy(request: NextRequest) {
27
+ const { pathname } = request.nextUrl;
28
+ const frappeUrl = process.env.FRAPPE_URL || 'http://127.0.0.1:${frappePort}';
29
+
30
+ // ─── Proxy Frappe API/assets/files requests ─────────────────────
31
+ const proxyPrefixes = ['/api/', '/assets/', '/files/', '/socket.io/'];
32
+ const shouldProxy = proxyPrefixes.some((prefix) => pathname.startsWith(prefix));
33
+
34
+ if (shouldProxy) {
35
+ const url = new URL(pathname + request.nextUrl.search, frappeUrl);
36
+ return NextResponse.rewrite(url, {
37
+ headers: request.headers,
38
+ });
39
+ }
40
+
41
+ // ─── Auth guard for SPA routes ─────────────────────────────────
42
+ const userId = request.cookies.get('user_id')?.value;
43
+ const isGuest = !userId || userId === 'Guest';
44
+
45
+ // Define public paths that don't require authentication
46
+ const publicPaths = ['/${spaName}/login', '/${spaName}/signup'];
47
+ const isPublicPath = publicPaths.some((p) =>
48
+ pathname.startsWith(p)
49
+ );
50
+
51
+ // Only guard /${spaName}/* routes
52
+ const isSpaRoute = pathname.startsWith('/${spaName}');
53
+
54
+ if (isSpaRoute) {
55
+ // Redirect unauthenticated users to login
56
+ if (isGuest && !isPublicPath) {
57
+ const loginUrl = new URL('/login', request.url);
58
+ loginUrl.searchParams.set('redirect-to', pathname);
59
+ return NextResponse.redirect(loginUrl);
60
+ }
61
+
62
+ // If logged in and trying to access login page, redirect to home
63
+ if (!isGuest && isPublicPath) {
64
+ return NextResponse.redirect(new URL('/${spaName}', request.url));
65
+ }
66
+ }
67
+
68
+ return NextResponse.next();
69
+ }
70
+
71
+ export const config = {
72
+ matcher: [
73
+ // Proxy Frappe API routes
74
+ '/api/:path*',
75
+ '/assets/:path*',
76
+ '/files/:path*',
77
+ '/socket.io/:path*',
78
+ // Guard SPA routes
79
+ '/${spaName}/:path*',
80
+ ],
81
+ };
82
+ `;
83
+ }
84
+ /**
85
+ * Generates Next.js 14/15 middleware.ts code (legacy, still works in Next.js 16).
86
+ *
87
+ * For Next.js 16+, prefer `generateProxy()` which uses the new proxy.ts convention.
88
+ */
89
+ function generateMiddleware(spaName) {
90
+ return `import { NextResponse } from 'next/server';
91
+ import type { NextRequest } from 'next/server';
92
+
93
+ /**
94
+ * Middleware to handle Frappe authentication for Next.js routes.
95
+ * NOTE: For Next.js 16+, consider using proxy.ts instead (see generateProxy).
96
+ *
97
+ * - Checks for 'user_id' cookie set by Frappe
98
+ * - Redirects unauthenticated users to Frappe login
99
+ * - Forwards all cookies to API routes for per-user SSR
100
+ */
101
+ export function middleware(request: NextRequest) {
102
+ const userId = request.cookies.get('user_id')?.value;
103
+ const isGuest = !userId || userId === 'Guest';
104
+
105
+ // Define public paths that don't require authentication
106
+ const publicPaths = ['/${spaName}/login', '/${spaName}/signup'];
107
+ const isPublicPath = publicPaths.some((path) =>
108
+ request.nextUrl.pathname.startsWith(path)
109
+ );
110
+
111
+ // Redirect unauthenticated users to login
112
+ if (isGuest && !isPublicPath) {
113
+ const loginUrl = new URL('/login', request.url);
114
+ loginUrl.searchParams.set('redirect-to', request.nextUrl.pathname);
115
+ return NextResponse.redirect(loginUrl);
116
+ }
117
+
118
+ // If logged in and trying to access login page, redirect to home
119
+ if (!isGuest && isPublicPath) {
120
+ return NextResponse.redirect(new URL('/${spaName}', request.url));
121
+ }
122
+
123
+ return NextResponse.next();
124
+ }
125
+
126
+ export const config = {
127
+ // Apply middleware to all routes under /${spaName} except static assets
128
+ matcher: ['/${spaName}/:path*'],
129
+ };
130
+ `;
131
+ }
132
+ //# sourceMappingURL=middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../src/ssr/middleware.ts"],"names":[],"mappings":";;AAUA,sCAoEC;AAOD,gDA0CC;AA/HD;;;;;;;;;GASG;AACH,SAAgB,aAAa,CAAC,OAAe,EAAE,aAAqB,IAAI;IACtE,OAAO;;;;;;;;;;;;kEAYyD,UAAU;;;;;;;;;;;;;;;;;;2BAkBjD,OAAO,cAAc,OAAO;;;;;mBAKpC,OAAO;6CACmB,OAAO;;;;;;;;;;;;+CAYL,OAAO;;;;;;;;;;;;;;;QAe9C,OAAO;;;CAGd,CAAC;AACF,CAAC;AAED;;;;GAIG;AACH,SAAgB,kBAAkB,CAAC,OAAe;IAChD,OAAO;;;;;;;;;;;;;;;;2BAgBkB,OAAO,cAAc,OAAO;;;;;;;;;;;;;;6CAcV,OAAO;;;;;;;6CAOP,OAAO;gBACpC,OAAO;;CAEtB,CAAC;AACF,CAAC"}
@@ -0,0 +1,33 @@
1
+ interface ProxyConfigOptions {
2
+ /** Path to bench's sites/common_site_config.json */
3
+ benchPath?: string;
4
+ /** Override Frappe webserver port (default: read from config or 8000) */
5
+ frappePort?: number;
6
+ }
7
+ /**
8
+ * Generate Next.js rewrite rules to proxy Frappe API requests during development.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * // next.config.mjs
13
+ * import { generateRewrites } from 'frappe-nextjs/ssr';
14
+ *
15
+ * const nextConfig = {
16
+ * async rewrites() {
17
+ * return generateRewrites({ frappePort: 8000 });
18
+ * },
19
+ * };
20
+ *
21
+ * export default nextConfig;
22
+ * ```
23
+ */
24
+ export declare function generateRewrites(options?: ProxyConfigOptions): {
25
+ source: string;
26
+ destination: string;
27
+ }[];
28
+ /**
29
+ * Generate a complete next.config.mjs string with Frappe proxy rewrites.
30
+ */
31
+ export declare function generateNextConfig(spaName: string, mode: 'ssr' | 'static', frappePort?: number): string;
32
+ export {};
33
+ //# sourceMappingURL=proxy-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy-config.d.ts","sourceRoot":"","sources":["../../src/ssr/proxy-config.ts"],"names":[],"mappings":"AAGA,UAAU,kBAAkB;IAC1B,oDAAoD;IACpD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,kBAAuB;;;IAwChE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,KAAK,GAAG,QAAQ,EACtB,UAAU,GAAE,MAAa,GACxB,MAAM,CAkCR"}
@@ -0,0 +1,133 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.generateRewrites = generateRewrites;
37
+ exports.generateNextConfig = generateNextConfig;
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ /**
41
+ * Generate Next.js rewrite rules to proxy Frappe API requests during development.
42
+ *
43
+ * @example
44
+ * ```ts
45
+ * // next.config.mjs
46
+ * import { generateRewrites } from 'frappe-nextjs/ssr';
47
+ *
48
+ * const nextConfig = {
49
+ * async rewrites() {
50
+ * return generateRewrites({ frappePort: 8000 });
51
+ * },
52
+ * };
53
+ *
54
+ * export default nextConfig;
55
+ * ```
56
+ */
57
+ function generateRewrites(options = {}) {
58
+ let frappePort = options.frappePort || 8000;
59
+ // Try to read port from bench config
60
+ if (!options.frappePort && options.benchPath) {
61
+ try {
62
+ const configPath = path.join(options.benchPath, 'sites', 'common_site_config.json');
63
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
64
+ if (config.webserver_port) {
65
+ frappePort = config.webserver_port;
66
+ }
67
+ }
68
+ catch {
69
+ // Use default port
70
+ }
71
+ }
72
+ const destination = `http://127.0.0.1:${frappePort}`;
73
+ return [
74
+ {
75
+ source: '/api/:path*',
76
+ destination: `${destination}/api/:path*`,
77
+ },
78
+ {
79
+ source: '/assets/:path*',
80
+ destination: `${destination}/assets/:path*`,
81
+ },
82
+ {
83
+ source: '/files/:path*',
84
+ destination: `${destination}/files/:path*`,
85
+ },
86
+ {
87
+ source: '/private/files/:path*',
88
+ destination: `${destination}/private/files/:path*`,
89
+ },
90
+ {
91
+ source: '/socket.io/:path*',
92
+ destination: `${destination}/socket.io/:path*`,
93
+ },
94
+ ];
95
+ }
96
+ /**
97
+ * Generate a complete next.config.mjs string with Frappe proxy rewrites.
98
+ */
99
+ function generateNextConfig(spaName, mode, frappePort = 8000) {
100
+ const outputConfig = mode === 'static'
101
+ ? `output: 'export',`
102
+ : `output: 'standalone',`;
103
+ return `import { dirname } from 'path';
104
+ import { fileURLToPath } from 'url';
105
+
106
+ const __dirname = dirname(fileURLToPath(import.meta.url));
107
+
108
+ /** @type {import('next').NextConfig} */
109
+ const nextConfig = {
110
+ ${outputConfig}
111
+ basePath: '/${spaName}',
112
+ trailingSlash: true,
113
+
114
+ turbopack: {
115
+ root: __dirname,
116
+ },
117
+
118
+ async rewrites() {
119
+ const frappeUrl = process.env.FRAPPE_URL || 'http://127.0.0.1:${frappePort}';
120
+
121
+ return [
122
+ { source: '/api/:path*', destination: \`\${frappeUrl}/api/:path*\` },
123
+ { source: '/assets/:path*', destination: \`\${frappeUrl}/assets/:path*\` },
124
+ { source: '/files/:path*', destination: \`\${frappeUrl}/files/:path*\` },
125
+ { source: '/socket.io/:path*', destination: \`\${frappeUrl}/socket.io/:path*\` },
126
+ ];
127
+ },
128
+ };
129
+
130
+ export default nextConfig;
131
+ `;
132
+ }
133
+ //# sourceMappingURL=proxy-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy-config.js","sourceRoot":"","sources":["../../src/ssr/proxy-config.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,4CAwCC;AAKD,gDAsCC;AA9GD,uCAAyB;AACzB,2CAA6B;AAS7B;;;;;;;;;;;;;;;;GAgBG;AACH,SAAgB,gBAAgB,CAAC,UAA8B,EAAE;IAC/D,IAAI,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,IAAI,CAAC;IAE5C,qCAAqC;IACrC,IAAI,CAAC,OAAO,CAAC,UAAU,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;QAC7C,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,EAAE,yBAAyB,CAAC,CAAC;YACpF,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;YAChE,IAAI,MAAM,CAAC,cAAc,EAAE,CAAC;gBAC1B,UAAU,GAAG,MAAM,CAAC,cAAc,CAAC;YACrC,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,mBAAmB;QACrB,CAAC;IACH,CAAC;IAED,MAAM,WAAW,GAAG,oBAAoB,UAAU,EAAE,CAAC;IAErD,OAAO;QACL;YACE,MAAM,EAAE,aAAa;YACrB,WAAW,EAAE,GAAG,WAAW,aAAa;SACzC;QACD;YACE,MAAM,EAAE,gBAAgB;YACxB,WAAW,EAAE,GAAG,WAAW,gBAAgB;SAC5C;QACD;YACE,MAAM,EAAE,eAAe;YACvB,WAAW,EAAE,GAAG,WAAW,eAAe;SAC3C;QACD;YACE,MAAM,EAAE,uBAAuB;YAC/B,WAAW,EAAE,GAAG,WAAW,uBAAuB;SACnD;QACD;YACE,MAAM,EAAE,mBAAmB;YAC3B,WAAW,EAAE,GAAG,WAAW,mBAAmB;SAC/C;KACF,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAgB,kBAAkB,CAChC,OAAe,EACf,IAAsB,EACtB,aAAqB,IAAI;IAEzB,MAAM,YAAY,GAAG,IAAI,KAAK,QAAQ;QACpC,CAAC,CAAC,mBAAmB;QACrB,CAAC,CAAC,uBAAuB,CAAC;IAE5B,OAAO;;;;;;;IAOL,YAAY;gBACA,OAAO;;;;;;;;oEAQ6C,UAAU;;;;;;;;;;;;CAY7E,CAAC;AACF,CAAC"}
@@ -0,0 +1,73 @@
1
+ import { FrappeClient } from '../client/FrappeClient';
2
+ import { FrappeClientConfig } from '../client/types';
3
+ /**
4
+ * Create a Frappe client configured for server-side usage in Next.js.
5
+ *
6
+ * Uses token-based authentication (API Key + Secret) since cookies are
7
+ * not available in Server Components, Route Handlers, or Server Actions.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * // lib/frappe.ts
12
+ * import { createServerClient } from 'frappe-nextjs/ssr';
13
+ *
14
+ * export const frappe = createServerClient({
15
+ * baseUrl: process.env.FRAPPE_URL!,
16
+ * token: {
17
+ * apiKey: process.env.FRAPPE_API_KEY!,
18
+ * apiSecret: process.env.FRAPPE_API_SECRET!,
19
+ * },
20
+ * });
21
+ * ```
22
+ *
23
+ * @example
24
+ * ```tsx
25
+ * // app/todos/page.tsx (Server Component)
26
+ * import { frappe } from '@/lib/frappe';
27
+ *
28
+ * export default async function TodosPage() {
29
+ * const todos = await frappe.getDocList({
30
+ * doctype: 'ToDo',
31
+ * fields: ['name', 'description', 'status'],
32
+ * limit: 20,
33
+ * });
34
+ *
35
+ * return (
36
+ * <ul>
37
+ * {todos.map((todo) => (
38
+ * <li key={todo.name}>{todo.description}</li>
39
+ * ))}
40
+ * </ul>
41
+ * );
42
+ * }
43
+ * ```
44
+ */
45
+ export declare function createServerClient(config: FrappeClientConfig): FrappeClient;
46
+ /**
47
+ * Create a Frappe client that forwards cookies from the incoming request.
48
+ * Useful for per-user SSR where you want to fetch data as the logged-in user.
49
+ *
50
+ * @example
51
+ * ```ts
52
+ * // app/api/user-data/route.ts
53
+ * import { createRequestClient } from 'frappe-nextjs/ssr';
54
+ * import { cookies } from 'next/headers';
55
+ *
56
+ * export async function GET() {
57
+ * const cookieStore = cookies();
58
+ * const client = createRequestClient({
59
+ * baseUrl: process.env.FRAPPE_URL!,
60
+ * cookies: cookieStore.toString(),
61
+ * });
62
+ *
63
+ * const user = await client.getLoggedUser();
64
+ * return Response.json({ user });
65
+ * }
66
+ * ```
67
+ */
68
+ export declare function createRequestClient(config: {
69
+ baseUrl: string;
70
+ cookies: string;
71
+ fetchImpl?: typeof fetch;
72
+ }): FrappeClient;
73
+ //# sourceMappingURL=server-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-client.d.ts","sourceRoot":"","sources":["../../src/ssr/server-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAErD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,kBAAkB,GAAG,YAAY,CAoB3E;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B,GAAG,YAAY,CAQf"}
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createServerClient = createServerClient;
4
+ exports.createRequestClient = createRequestClient;
5
+ const FrappeClient_1 = require("../client/FrappeClient");
6
+ /**
7
+ * Create a Frappe client configured for server-side usage in Next.js.
8
+ *
9
+ * Uses token-based authentication (API Key + Secret) since cookies are
10
+ * not available in Server Components, Route Handlers, or Server Actions.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * // lib/frappe.ts
15
+ * import { createServerClient } from 'frappe-nextjs/ssr';
16
+ *
17
+ * export const frappe = createServerClient({
18
+ * baseUrl: process.env.FRAPPE_URL!,
19
+ * token: {
20
+ * apiKey: process.env.FRAPPE_API_KEY!,
21
+ * apiSecret: process.env.FRAPPE_API_SECRET!,
22
+ * },
23
+ * });
24
+ * ```
25
+ *
26
+ * @example
27
+ * ```tsx
28
+ * // app/todos/page.tsx (Server Component)
29
+ * import { frappe } from '@/lib/frappe';
30
+ *
31
+ * export default async function TodosPage() {
32
+ * const todos = await frappe.getDocList({
33
+ * doctype: 'ToDo',
34
+ * fields: ['name', 'description', 'status'],
35
+ * limit: 20,
36
+ * });
37
+ *
38
+ * return (
39
+ * <ul>
40
+ * {todos.map((todo) => (
41
+ * <li key={todo.name}>{todo.description}</li>
42
+ * ))}
43
+ * </ul>
44
+ * );
45
+ * }
46
+ * ```
47
+ */
48
+ function createServerClient(config) {
49
+ if (!config.baseUrl) {
50
+ throw new Error('createServerClient requires a baseUrl. ' +
51
+ 'Set FRAPPE_URL in your environment variables.');
52
+ }
53
+ if (!config.token) {
54
+ throw new Error('createServerClient requires token auth (apiKey + apiSecret). ' +
55
+ 'Set FRAPPE_API_KEY and FRAPPE_API_SECRET in your environment variables.');
56
+ }
57
+ return new FrappeClient_1.FrappeClient({
58
+ ...config,
59
+ // Use global fetch in Node.js (available in Node 18+)
60
+ fetchImpl: config.fetchImpl || globalThis.fetch.bind(globalThis),
61
+ });
62
+ }
63
+ /**
64
+ * Create a Frappe client that forwards cookies from the incoming request.
65
+ * Useful for per-user SSR where you want to fetch data as the logged-in user.
66
+ *
67
+ * @example
68
+ * ```ts
69
+ * // app/api/user-data/route.ts
70
+ * import { createRequestClient } from 'frappe-nextjs/ssr';
71
+ * import { cookies } from 'next/headers';
72
+ *
73
+ * export async function GET() {
74
+ * const cookieStore = cookies();
75
+ * const client = createRequestClient({
76
+ * baseUrl: process.env.FRAPPE_URL!,
77
+ * cookies: cookieStore.toString(),
78
+ * });
79
+ *
80
+ * const user = await client.getLoggedUser();
81
+ * return Response.json({ user });
82
+ * }
83
+ * ```
84
+ */
85
+ function createRequestClient(config) {
86
+ return new FrappeClient_1.FrappeClient({
87
+ baseUrl: config.baseUrl,
88
+ headers: {
89
+ Cookie: config.cookies,
90
+ },
91
+ fetchImpl: config.fetchImpl || globalThis.fetch.bind(globalThis),
92
+ });
93
+ }
94
+ //# sourceMappingURL=server-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-client.js","sourceRoot":"","sources":["../../src/ssr/server-client.ts"],"names":[],"mappings":";;AA6CA,gDAoBC;AAwBD,kDAYC;AArGD,yDAAsD;AAGtD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,SAAgB,kBAAkB,CAAC,MAA0B;IAC3D,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CACb,yCAAyC;YACzC,+CAA+C,CAChD,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CACb,+DAA+D;YAC/D,yEAAyE,CAC1E,CAAC;IACJ,CAAC;IAED,OAAO,IAAI,2BAAY,CAAC;QACtB,GAAG,MAAM;QACT,sDAAsD;QACtD,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC;KACjE,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,SAAgB,mBAAmB,CAAC,MAInC;IACC,OAAO,IAAI,2BAAY,CAAC;QACtB,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,OAAO,EAAE;YACP,MAAM,EAAE,MAAM,CAAC,OAAO;SACvB;QACD,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC;KACjE,CAAC,CAAC;AACL,CAAC"}