Closed Er1c0 closed 2 years ago
@Er1c0 Hi, could you provide a little more info about your setup and more specifically:
Thanks!
I've just created a demo vue project with npm init vue@latest
and everything seems to be loading OK.
Just created a project with nuxt v2 and v3. Import in nuxt v3 works fine (it is using vite).
But nuxt v2 uses older webpack version and requires explicitly to point to the sdk bundle. Changing your import path to one of the below, should work:
// for execution in browser
import PocketBase from "pocketbase/dist/pocketbase.es"
// or if you are using server-side-rendering
import PocketBase from "pocketbase/dist/pocketbase.cjs"
I'll investigate the issue further and will search if there is a way to avoid this.
Hi,
I think the error is the same for NextJS.
The setup is as follows:
"next": "12.2.2",
"pocketbase": "^0.1.2",
"react": "18.2.0",
"react-dom": "18.2.0"
node version: v18.2.0
How to reproduce:
npx create-next-app@latest --typescript
# Enter folder
npm install --save pocketbase
# Update file pages/index.ts accordingly
npm run dev
Error is as follows:
Unhandled Runtime Error
TypeError: pocketbase__WEBPACK_IMPORTED_MODULE_3___default(...) is not a constructor
As suggested, using client / ssr is as follows:
// for execution in browser
import PocketBase from "pocketbase/dist/pocketbase.es"
# Error
Server Error
SyntaxError: Unexpected token 'export'
This error happened while generating the page. Any console logs will be displayed in the terminal window.
// or if you are using server-side-rendering
import PocketBase from "pocketbase/dist/pocketbase.cjs"
# Does work with initializing and requesting some data
The SSR import does work. Does this mean that all http requests (from the library) should be done on the server side?
P.s. I'm having some problems to import the types from your typescript definition as well.
@mbecker Thank you. I'll try to investigate it and will fix it tomorrow. I may need to rework the distributed bundles and eventually will add umd export.
@Er1c0, @mbecker I've just released a v0.2.0 of the SDK that comes with rewritten core, removing all 3rd party commonjs dependencies (axios, qs) and uses only native js primitives that are available in browser, node, demo, react-native, etc.
As a bonus the size was also reduced almost 3.5 times (75kb -> 23kb or ~5kb gzipped!).
The documentation was also updated to reflect the change. To import it in your project it should be enough to do:
// Using ES modules (default)
import PocketBase from 'pocketbase'
// OR if you are using CommonJS modules
const PocketBase = require('pocketbase/cjs')
Since fetch()
is supported only in Node17/18+, if you want to use the library with earlier node versions (note that Node16 active support will end somewhere at the end of this year), you will have to import a polifill beforehand. I recommend cross-fetch:
import 'cross-fetch/polyfill';
There are very minor breaking changes related to the error response. Now is normalized and will always return ClientErrorResponse
(you could red more in the caveats section - https://github.com/pocketbase/js-sdk#caveats).
If you are still having difficulties loading the SDK, please let me know and I'll investigate it. I've tested with vite, vue-cli generated project, nuxt2, nuxt3, nextjs, node16 + polifill, node 18.
Hi @ganigeorgiev ,
thanks for your great work! Seems to work. Even with my current node version v16.13.0 and without any polyfill. Does this makes sense?
Anyways, I'm using the library with NextJS and NextAuth.js (and Strava ;-) ). The user data returned from the method "client.Users.authViaOAuth2" has the following TypeScript definitions:
type UserAuthResponse = {
[key: string]: any;
token: string;
user: User;
};
declare class User extends BaseModel {
email: string;
verified: boolean;
lastResetSentAt: string;
lastVerificationSentAt: string;
profile: null | Record;
/**
* @inheritdoc
*/
load(data: {
[key: string]: any;
}): void;
}
declare class Record extends BaseModel {
[key: string]: any;
"@collectionId": string;
"@collectionName": string;
"@expand": {
[key: string]: any;
};
/**
* @inheritdoc
*/
load(data: {
[key: string]: any;
}): void;
}
The internal user's profile structure of PocketBase has the fields "name" and "avatar" which is not included in the definition. Would be nice to include it.
Should I create a new feature request for that?
Additional, the definition for the user's profile "name" and "avatar" are also not explicitly defined in the main project. Plus, the user's profile is not created / updated with "name" and "avatar" by using an OAuth provider. I'm creating an additional feature request in the main repo.
Again, great work!
About the polyfill - probably nextjs or the bundler already includes it (practically as long there is something like global.fetch = myFetchPolyfill
you are ok).
About the name
and avatar
fields - there are not part of the user model. In the UserAuthResponse
type the OAuth provider profile will be appended as meta
object where you'll find the OAuth2 avatar
(TS currently allows this because of the [key: string]: any;
definition). Since this meta
key is currently set only when you are authorized via OAuth2 it is not "fixed" in place, but I'll consider changing that and at least update the definition to be similar to the @expand
Record prop, aka. UserAuthResponse could be:
type UserAuthResponse = {
[key: string]: any;
token: string,
user: User,
meta: {
[key: string]: any;
},
};
Hi,
thanks for your feedback. Yes, I was aware of the meta
Object. But, I would like to have a more fixed value for the user's profiles field name
and avatar
. If the user decides to use another OAuth provider the next time, the name
and avatar
may change. Would be quite confusing ;-)
Again, I think it's a bigger question if the user's profile model should be used as defined the database with the fields name
and avatar
and if signing up with an OAuth provider for the first time should fill the values from the OAuth provider's information.
The additional meta
object in the TypeScript definition looks good! Thanks for that!
I think you are mixing the user profile with the OAuth2 authenticated profile.
Each user has a system profile
collection attached to them (see the definition of class User
). This profile is where name
and avatar
fields are coming from. From the admin UI, you can define whatever fields you want. The only field that you cannot change is user.profile.userId
(because it is marked as system
).
Since this profile object is practically a Collection Record
with dynamic fields, there is no way to "fix" its definition. You can define your own and cast it if you need to.
To update the profile, you could call:
const authResponse = await client.Users.authViaEmail("test@example.com", 123456);
const updatedRecord = await client.Records.update("profiles", authResponse.user.profile.id, {
name: "example",
someOtherFieldDefinedInTheAdmin: 123,
...
});
The OAuth2 profile is just returned in the response. It is not persisted and it is up to the developer to "transfer" its fields if he/she finds them useful and put them in the PocketBase user's profile.
You can also find some information about the custom profile fields and the profile collection here - https://pocketbase.io/docs/manage-users/#custom-fields
Hi, thanks again for your feedback and more than detailed answers! Really appreciate your effort!
My understanding at the beginning was that that the sign up process via an OAuth provider creates / updates the user's profile collection with the given name
and avatar
. In your OAuth provider implementation likes "google" you are explicitly unmarshaling the username and profile pictures; my understanding of your idea was that you want to use the data as the user's profile information in pocketbase (if not, the data from the oauth provider would be quite useless and you are taking only the email address).
Now, I think to understand your design philosophy ;-)
Maybe last question for updating the collection profile with an avatar / image file: I'm now checking at the sign in flow at the client side if the user's collection profile has a field meta.avatarUrl
; if yes, I'm downloading it and trying to update the user's profile as follows:
bodyParams["name"] = meta['name'];
const image = await fetch(meta['avatarUrl']);
bodyParams["avatar"] = await image.blob();
await client.Records.update("profiles", user.profile.id, bodyParams, {"enctype": "multipart/form-data"});
Which file encoding should the image / file has to be saved by pocketbase?
Thanks for your help and again great work!
The OAuth profile is not stable and could change from login to login.
In addition, as I mentioned, the user profile collection and the name
and avatar
fields are just common defaults. Developers can change, remove and add new fields from the "Admin UI > Users > Edit profile collection".
About downloading and uploading a remote image in the browser - yes, you can create a image blob but you need to sent it as part of a FormData
object.
I don't know what {"enctype": "multipart/form-data"}
is and why you decided to set it to this value. The 4th argument is for additional query parameters that will be sent with the request.
To upload your file you need to change your bodyParams
to be a FormData object and that's it. For example:
const bodyParams = new FormData();
bodyParams.append("name", meta["name"]);
bodyParams.append("avatar", blob);
await client.Records.update("profiles", user.profile.id, bodyParams);
Alternatively, you could also remove the default avatar
profile collection field and add your own avatarUrl
text/url field and just store the OAuth2 profile avatar url.
You could also find a file upload example here - https://pocketbase.io/docs/files-handling/#uploading-files
I'm sorry. With "at client side" I mean the NextJS backend app (nodejs) handling the authentication flow. Sorry for the confusing.
I've managed to work it at the backend app (nodejs) with the npm package form-data as follows:
import FormData from "form-data";
const formData = new FormData();
formData.append("name", meta["name"]);
const image = await fetch(meta['avatarUrl']);
formData.append("avatar", image.body, {
filename: "large.jpg",
contentType: "image/jpeg"
});
await client.Records.update("profiles", user.profile.id, formData);
Maybe it helps anyone. Thank you very much for your help and cheers!
vue