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.
- package/README.md +90 -0
- package/dist/bin/cli.d.ts +3 -0
- package/dist/bin/cli.d.ts.map +1 -0
- package/dist/bin/cli.js +156 -0
- package/dist/bin/cli.js.map +1 -0
- package/dist/build/boilerplates.d.ts +12 -0
- package/dist/build/boilerplates.d.ts.map +1 -0
- package/dist/build/boilerplates.js +261 -0
- package/dist/build/boilerplates.js.map +1 -0
- package/dist/build/build.d.ts +27 -0
- package/dist/build/build.d.ts.map +1 -0
- package/dist/build/build.js +172 -0
- package/dist/build/build.js.map +1 -0
- package/dist/build/context-generator.d.ts +13 -0
- package/dist/build/context-generator.d.ts.map +1 -0
- package/dist/build/context-generator.js +76 -0
- package/dist/build/context-generator.js.map +1 -0
- package/dist/build/hooks-patcher.d.ts +11 -0
- package/dist/build/hooks-patcher.d.ts.map +1 -0
- package/dist/build/hooks-patcher.js +78 -0
- package/dist/build/hooks-patcher.js.map +1 -0
- package/dist/build/index.d.ts +8 -0
- package/dist/build/index.d.ts.map +1 -0
- package/dist/build/index.js +33 -0
- package/dist/build/index.js.map +1 -0
- package/dist/build/init.d.ts +27 -0
- package/dist/build/init.d.ts.map +1 -0
- package/dist/build/init.js +175 -0
- package/dist/build/init.js.map +1 -0
- package/dist/build/nginx-generator.d.ts +22 -0
- package/dist/build/nginx-generator.d.ts.map +1 -0
- package/dist/build/nginx-generator.js +114 -0
- package/dist/build/nginx-generator.js.map +1 -0
- package/dist/build/supervisor-generator.d.ts +31 -0
- package/dist/build/supervisor-generator.d.ts.map +1 -0
- package/dist/build/supervisor-generator.js +105 -0
- package/dist/build/supervisor-generator.js.map +1 -0
- package/dist/client/FrappeClient.d.ts +143 -0
- package/dist/client/FrappeClient.d.ts.map +1 -0
- package/dist/client/FrappeClient.js +446 -0
- package/dist/client/FrappeClient.js.map +1 -0
- package/dist/client/index.d.ts +3 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +21 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/types.d.ts +140 -0
- package/dist/client/types.d.ts.map +1 -0
- package/dist/client/types.js +17 -0
- package/dist/client/types.js.map +1 -0
- package/dist/hooks/FrappeProvider.d.ts +41 -0
- package/dist/hooks/FrappeProvider.d.ts.map +1 -0
- package/dist/hooks/FrappeProvider.js +48 -0
- package/dist/hooks/FrappeProvider.js.map +1 -0
- package/dist/hooks/index.d.ts +8 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +17 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/useFrappeAuth.d.ts +37 -0
- package/dist/hooks/useFrappeAuth.d.ts.map +1 -0
- package/dist/hooks/useFrappeAuth.js +111 -0
- package/dist/hooks/useFrappeAuth.js.map +1 -0
- package/dist/hooks/useFrappeCall.d.ts +26 -0
- package/dist/hooks/useFrappeCall.d.ts.map +1 -0
- package/dist/hooks/useFrappeCall.js +47 -0
- package/dist/hooks/useFrappeCall.js.map +1 -0
- package/dist/hooks/useFrappeDoc.d.ts +37 -0
- package/dist/hooks/useFrappeDoc.d.ts.map +1 -0
- package/dist/hooks/useFrappeDoc.js +79 -0
- package/dist/hooks/useFrappeDoc.js.map +1 -0
- package/dist/hooks/useFrappeDocList.d.ts +37 -0
- package/dist/hooks/useFrappeDocList.d.ts.map +1 -0
- package/dist/hooks/useFrappeDocList.js +65 -0
- package/dist/hooks/useFrappeDocList.js.map +1 -0
- package/dist/hooks/useFrappeFileUpload.d.ts +40 -0
- package/dist/hooks/useFrappeFileUpload.d.ts.map +1 -0
- package/dist/hooks/useFrappeFileUpload.js +68 -0
- package/dist/hooks/useFrappeFileUpload.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/ssr/index.d.ts +4 -0
- package/dist/ssr/index.d.ts.map +1 -0
- package/dist/ssr/index.js +13 -0
- package/dist/ssr/index.js.map +1 -0
- package/dist/ssr/middleware.d.ts +18 -0
- package/dist/ssr/middleware.d.ts.map +1 -0
- package/dist/ssr/middleware.js +132 -0
- package/dist/ssr/middleware.js.map +1 -0
- package/dist/ssr/proxy-config.d.ts +33 -0
- package/dist/ssr/proxy-config.d.ts.map +1 -0
- package/dist/ssr/proxy-config.js +133 -0
- package/dist/ssr/proxy-config.js.map +1 -0
- package/dist/ssr/server-client.d.ts +73 -0
- package/dist/ssr/server-client.d.ts.map +1 -0
- package/dist/ssr/server-client.js +94 -0
- package/dist/ssr/server-client.js.map +1 -0
- 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"}
|
package/dist/index.d.ts
ADDED
|
@@ -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 @@
|
|
|
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"}
|