Ember.js - get value of `--proxy` parameter passed into `ember server` - ember.js

I need my Ember app to make an AJAX request to the API backend it is proxying to. I have some kludgy code that inserts one of several hard-coded values but I'd much rather the AJAX request just grabs the value passed into --proxy when I run ember server.
Does anyone know if there's a way to retrieve this value from within Ember?

It appears it is not exposed, at least not by any public API. If you don't mind a bit of duplication at the command line, this would work:
$ proxy=http://myproxy ember server --proxy http://myproxy
The env params need to come before ember server or else ember throws them away.
// app/config/environment.js
const proxy = process.env.proxy;
const ENV = {
APP: {
// Here you can pass flags/options to your application instance
// when it is created
proxy,
},
};
// app/routes/my-route.js (or wherever)
import ENV from 'myAppName/config/environment';
export default Route.extend({
model() {
return ENV.APP.proxy;
},
});
You can of course access process.env.proxy from anywhere, but this is cleaner and keeps the property where it belongs.

You can get it in the file config/environment.js.
const proxy = (process.argv.indexOf('--proxy') != -1) ? process.argv[process.argv.indexOf('--proxy') + 1] : '';

Related

How to use Pinia outside a component in js file

I am migrating from vue 4.x to pinia, one of my file needs api key from store.
But I can't make it work even though I follow the Pinia documentation .
here is how I use pinia
// Repository.ts
import axios from "axios";
import { createPinia } from 'pinia'
import { useAuthStore } from '../stores/auth-store'
const pinia=createPinia();
let authStore = useAuthStore(pinia);
const baseURL = 'http://127.0.0.1:5678/res-api';
export default axios.create({
baseURL,
headers:{"Authorization":"Bearer " + authStore.getToken,
"Accept":"application/json"},
});
Expected result : to get the token from the store.
Console error
Uncaught ReferenceError: Cannot access 'useAuthStore' before initialization
at Repository.ts:6:17
Note: this working inside a component
You can solve this by importing the store inside the interceptors
import axios from "axios";
import { useAuthStore } from '../stores/auth-store';
const axiosClient = axios.create({
baseURL: 'http://127.0.0.1:5678/res-api'
});
axiosClient.interceptors.request.use((config) => {
const authStore = useAuthStore();
config.headers.Authorization = `Bearer ${authStore.getToken}`;
config.headers.Accept = "application/json";
return config
})
export default axiosClient;
This discussion may help you: Go to GitHub discussion
According to the documentation the pinia you created must go as a parameter to app.use. Not only that, but useAuthStore must be a store defined with defineStore and must not take a parameter. I'll leave a link that can help you, it doesn't create the store but you can browse the side menu to see several examples.
https://pinia.vuejs.org/core-concepts/outside-component-usage.html
Here is my sample project to demo the issue: https://codesandbox.io/s/infallible-shamir-sxrlb9.
The main cause here is that you cannot use Pinia's stores before passing it to the Vue's app. So given following code:
const pinia = createPinia(); // line 1
createApp(App).use(pinia).mount("#app"); // line 2
You cannot trigger any store in between line 1 and 2, but only after line 2.
In your code, likely you trigger an axios call before creating Vue app/add Pinia to Vue app. Please try to delay that axios call to trigger after Vue app's setup is complete.

Apollo client useMutation in expo renders twice for every call

I have a basic expo app with React Navigation.
In the top function Navigation I am initiating a useMutation call to an Apollo server like so:
import { callToServer, useMutation } from '../graphQL';
function Navigation() {
console.log("RENDERED");
const [call] = useMutation(callToServer);
call({ variables: { uid: 'xyz', phoneNumber: '123' } });
...
And my GraphQL settings is as follows:
import {
ApolloClient,
createHttpLink,
InMemoryCache,
useMutation,
} from '#apollo/client';
import { onError } from '#apollo/client/link/error';
import { callToServer } from './authAPI';
const cache = new InMemoryCache();
const httpLink = createHttpLink({
uri: `XXXXXXX/my-app/us-central1/graphql`,
});
const errorLink = onError(({ graphQLErrors, networkError }) => {
...
});
const client = new ApolloClient({
cache,
link: errorLink.concat(httpLink),
});
export {
useMutation,
callToServer,
};
export default client;
I want to clarify that I removed the httpLink from the client setting and I still get the two renders per call. I can see in the console that console.log("RENDERED") prints three times. Once when the app loads (normal) and twice after the useMutation call (not normal?)
What's going on here? Why is react re-renders twice per useMutation call? How do I avoid it?
UPDATE
I did further digging and it seems that useMutation does indeed cause the App to render twice - once when the request is sent, and once when it receives a response. I'm not sure I'm loving this default behavior which seems to have no way to disable. Why not let us decide if we want to re-render the App?
If someone has more insight to offer, Id love to hear about it.
Probably it's too late and maybe you've already found the solution, but still...
As I see you do not need data returned from mutation in the code above. In this case you can use useMutation option "ignoreResults" and set it to "true". So mutation will not update "data" property and will not cause any render.

Ember-simple-auth: Use Custom cookie session to store additional token

Using: ember-cli v2.5, ember-simple-auth v1.1.0
I got trouble understanding if I can properly store additional token inside a custom ember-simple-auth's cookie based session-store.
I'm trying to store a shopping-cart token to be sure it survives browser refresh.
I started to create a shopping-cart service to handle init, add, remove etc ... regarding if the session has a token.
Here is my app/session-stores/application.js
// app/session-stores/application.js
import Cookie from 'ember-simple-auth/session-stores/cookie';
export default Cookie.extend({
orderToken: null
});
Doesn't seems to be used. The session service still use the adaptive store.
Here is my shopping-cart service
// app/services/shopping-cart.js
import Ember from 'ember';
export default Ember.Service.extend({
store: Ember.inject.service('store'),
session: Ember.inject.service('session'),
basket: null,
[...]
init() {
this._super(...arguments);
let orderToken = this.get('session.orderToken'); // First try
// let orderToken = this.get('session.store.orderToken'); // Second Try
if (orderToken) {
this.get('store').findRecord('order', orderToken).then((order) => {
this.set('basket', order);
})
}
},
[...]
_createBasket() {
return this.get('store').createRecord('order', {}).save().then((order) => {
this.set('basket', order);
this.set('session.orderToken', order.token); // First try
// this.set('session.store.orderToken', order.token); // Second Try
});
}
})
Then the idea will be to inject the service wherever I need. Unfortunately, It doesn't work, and I don't really know if I can do it or if it's the right way to do it.
Any advices, answers will be much appreciate !
I am currently using ember-cookie and it's working like a charm. I am juste trying to play with ember-simple-auth and understand all my possibilities.

Get two versions of ember-simple-auth to play well together

We're working with two ember applications that each run different version of ember and ember-simple-auth, and want to get ember-simple-auth to work well with both version.
The old app
Ember 1.8.1
Ember-simple-auth 0.7.3
The new app
Ember 2.3.1
Ember-simple-auth 1.0.1
Uses cookie session store
We trying to change the session API for the older version so that it stores the access and refresh tokens correctly so the new app can use it.
So far, we’ve tried overriding the setup and updateStore methods to work with the authenticated nested object but are still running into issues.
Disclaimer - Patrick Berkeley and I work together. We found a solution after posting this question that I figured I would share.
In order for a 0.7.3 version of ember-simple-auth's cookie store to play nicely with a 1.0.0 version, we did have to normalize how the cookie was being formatted on the app with the earlier version in a few key places, mostly centered around the session object (the 0.7.3 session is an ObjectProxy that can be extended in the consuming app to create your own custom session).
The methods that we needed to override, centered around the structure of data being passed to the cookie store to persist and what was being returned when a session was being restored. The key difference is on version 0.7.3, the access_token, etc is stored top-level on the content object property of the session. With 1.0.0. this is nested inside another object inside content with the property name of authenticated. We therefore needed to ensure that everywhere we were making the assumption to set or get the access_token at the top level, we should instead retrieve one level deeper. With that in mind, we came up with these methods being overridden in our custom session object:
// alias access_token to point to new place
access_token: Ember.computed.alias('content.authenticated.access_token'),
// overridden methods to handle v2 cookie structure
restore: function() {
return new Ember.RSVP.Promise((resolve, reject) => {
const restoredContent = this.store.restore();
const authenticator = restoredContent.authenticated.authenticator;
if (!!authenticator) {
delete restoredContent.authenticated.authenticator;
this.container.lookup(authenticator).restore(restoredContent.authenticated).then(function(content) {
this.setup(authenticator, content);
resolve();
}, () => {
this.store.clear();
reject();
});
} else {
this.store.clear();
reject();
}
});
},
updateStore: function() {
let data = this.content;
if (!Ember.isEmpty(this.authenticator)) {
Ember.set(data, 'authenticated', Ember.merge({ authenticator: this.authenticator }, data.authenticated || {}));
}
if (!Ember.isEmpty(data)) {
this.store.persist(data);
}
},
setup(authenticator, authenticatedContent, trigger) {
trigger = !!trigger && !this.get('isAuthenticated');
this.beginPropertyChanges();
this.setProperties({
isAuthenticated: true,
authenticator
});
Ember.set(this, 'content.authenticated', authenticatedContent);
this.bindToAuthenticatorEvents();
this.updateStore();
this.endPropertyChanges();
if (trigger) {
this.trigger('sessionAuthenticationSucceeded');
}
},
clear: function(trigger) {
trigger = !!trigger && this.get('isAuthenticated');
this.beginPropertyChanges();
this.setProperties({
isAuthenticated: false,
authenticator: null
});
Ember.set(this.content, 'authenticated', {});
this.store.clear();
this.endPropertyChanges();
if (trigger) {
this.trigger('sessionInvalidationSucceeded');
}
},
bindToStoreEvents: function() {
this.store.on('sessionDataUpdated', (content) => {
const authenticator = content.authenticated.authenticator;
this.set('content', content);
if (!!authenticator) {
delete content.authenticated.authenticator;
this.container.lookup(authenticator).restore(content.authenticated).then((content) => {
this.setup(authenticator, content, true);
}, () => {
this.clear(true);
});
} else {
this.clear(true);
}
});
}.observes('store'),
This took us most of the way there. We just needed to ensure that the authenticator name that we use matches the name on 1.0.0. Instead of 'simple-auth-authenticator:oauth2-password-grant', we needed to rename our authenticator via an initializer to 'authenticator:oauth2'. This ensures that the apps with the newer version will be able to handle the correct authenticator events when the cookie session data changes. The initializer logic is simple enough:
import OAuth2 from 'simple-auth-oauth2/authenticators/oauth2';
export default {
name: 'oauth2',
before: 'simple-auth',
initialize: function(container) {
container.register('authenticator:oauth2', OAuth2);
}
};
The above satisfies our needs- we can sign in to an app using ember-simple-auth 0.7.3 and have the cookie session stored and formatted properly to be handled by another app on ember-simple-auth 1.0.0.
Ideally, we would just update the Ember and Ember Simple Auth versions of the app though business needs and the fact that we wanted to focus our energies on the v2 versions (which are completely fresh and new code bases) propelled us to go down this path.

Separate environment config in Ember

I'm using the ember-cli to build my app, which gives me a nice app.js file that I can server up on a static asset server. What is the most idiomatic way to allow for a separate configuration at deployment time?
For example, I might tell the consumer of my app.js file to include an extra config.[js|json] file which will get loaded, and the values from that file would go into the ENV object... so that I can point the app at a different REST endpoint, for example (QA, Sandbox, Pre-release, etc) without re-compiling.
I figure there must be a way, I'm just not seeing it. I get that there is the config/environment.js file, but that gets compiled into the dist folder. I'm looking for something that sits next to the packaged JS. I can certainly hack something together, so I'm not looking for a hack. An ember-cli-addon, perhaps? I figure there must be an "ember way" to do this.
I'm just not finding it :)
Ok, here is what I did. Basically, I allow some settings to be overridden by the host application. I register an initializer to jam them into the configuration object, and then I use the config options like normal. It looks a little something like this:
config/environment.js
// This is just normal ENV.APP configuration stuff. Nothing odd here
module.exports = function(environment) {
var ENV = {
// snip
APP: {
API_HOST: 'http://defaultAPIHost.com',
AUTH_PROVIDER: 'http://defaultAuthProvider.com'
}
};
return ENV;
};
app/initializers/parameter-overrides.js
import config from '../config/environment';
// This is the custom stuff. If the values have been defined globally,
// override them on the config object. I suppose this can be done a
// bit more dynamically, but this explicit code is for illustrative purposes.
export function initialize() {
let apiOverride = window.MyAppEnv && window.MyAppEnv.API_HOST;
let authOverride = window.MyAppEnv && window.MyAppEnv.AUTH_PROVIDER;
config.APP.API_HOST = apiOverride || config.APP.API_HOST;
config.APP.AUTH_PROVIDER = authOverride || config.APP.AUTH_PROVIDER;
}
export default {
name: 'parameter-overrides',
initialize: initialize
};
app/adapters/application
import DS from 'ember-data';
import config from '../config/environment';
// Then consume the config properties as you normally would
export default DS.RESTAdapter.extend({
host: config.APP.API_HOST,
namespace: "api"
});
Now, the hosting application can include this in the page, and it will override the values from the config/environment.js:
<script type="text/javascript">
// Override this value in production to the proper API host and Auth host
window.MyAppEnv = {
AUTH_PROVIDER: null, //'http://oauthhost.com/OAuth2'
API_HOST: null //"http://apihost.com"
};
</script>
Is this a reasonable approach? Is there something better out there?