
Security News
The Hidden Blast Radius of the Axios Compromise
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.
@pinpt/data-manager
Advanced tools
Pinpoint Data Manager for React
This package provides a set of web browser based JavaScript utilities for use with Pinpoint data.
This package targets the web browser and should be installed as a node module in a React project:
npm install @pinpt/data-manager
The following are goals of this package:
This project exposes the following major components:
All of these components are exposed so that they can be used directly. However, the app will interact mainly with the provided React Context and Hook.
The DataManager exposes a React Context component which should be used in the application as follows:
function App() {
return (
<DataManager.Provider
graphAPI="https://graph.api.edge.pinpoint.com/graphql"
eventAPI="wss://event.api.edge.pinpoint.com/ws"
deviceID={window.PinpointEvent.deviceid()}
sessionID={window.PinpointEvent.sessionid()}
customerID={window.PinpointAuth.customer.id}
userID={window.PinpointAuth.user.id}
>
<div className="App">
<App />
</div>
</DataManager.Provider>
);
}
The properties should be dynamically passed instead of hard coded. The deviceID and sessionID should be passed from the event-api beacon using the values from window.PinpointEvent.deviceid() and window.PinpointEvent.sessionid().
The useData hook will expose data from pluggable data managers in a generic way. The features of the hook:
The hook takes the following arguments:
model: (string) - the name of the model such as admin.Userdataprops?: (undefined | string | FilterQuery | Function | Promise) - pass a string with the _id to do a findOne or pass a FilterQuery to do a findMany. pass or skip the parameter if you want to load later.opts?: (FindOptions | Function) - optional opts for controlling the query, can be callback function which returns FindOptions (use with dependencies)The FilterQuery has the following properties:
filters: (string[]) - the filter expressionparams?: (any[]) - the filter parameters to fill in the placeholders from the filter expressionThe DataOptionalProps interface has the following properties:
cache?: (undefined | false) - set to false to turn off caching of data in the request. defaults to true.optimistic?: (undefined | false | number) - set to false to turn off optimistic refetching of cached data. defaults to true. set to a positive number to control the number of milliseconds before triggering the refreshpaginate?: (PaginateOptions) - set the a value to paginate for fetchMany requestsThe PaginateOptions interface has the following properties:
max?: (number) - set to a number to control the per request page size. defaults to 100 if not provided.The useData hook will return an object with the following properties:
data: (any) - the result data, which is null if not foundloading: (boolean) - true if the data is loading, false if loadedpending: (boolean) - true if the data is pending because no parameters were passedcached: (boolean) - true if the data returned was from the cache and false if from the networkoffline: (boolean) - true if the data returned was from the cache and you're offlineerror: (Error) - null if no error or an Error if an error fetching the datapagination: (DataPagination) - if the query was paginated, the pagination details or null if notsetID: (val: string) => void - change the ID of the query dynamicallysetFilter: (val: FilterQuery) => void - change the filter of the query dynamicallyThe DataPagination interface has the following properties:
offset: number - the offset number in the total result settotalCount: number - the total number of records matching the queryhasNextPage: boolean - true if there is more data beyond the current result going forwardhasPreviousPage: boolean - true if there is more data beyond the current result going backwardsstartCursor: string - the opaque cursor for the beginning of the pageendCursor: string - the opaque cursor for the end of the pagenext: (append?: boolean, position?: 'before' | 'after') => Promise - a function to advance the page forwards. if append = false, will prepend (position=before) or append (position=after) to the previous pageprevious: () => Promise - a function to advance the page backwardsExample usage for returning a specific record when you have an ID:
const UserComponent = () => {
const { data: user, loading, error } = useData<IAdminUser>('admin.User', 'ab980e7028c8b147');
if (loading) {
return <div>Loading</div>;
}
if (error) {
return <div>{error.message}</div>;
}
return (
<div>{user?.profile.first_name} {user?.profile.last_name}</div>
);
};
Example usage for returning multiple results with a filter:
const UserListComponent = () => {
const { data: users, loading, error } = useData<IAdminUser[]>('admin.User', { filters: [ 'active = ?' ], params: [ true ] } );
if (loading) {
return <div>Loading</div>;
}
if (error) {
return <div>{error.message}</div>;
}
return (
<>
<pre style={{padding: '10px'}}>{JSON.stringify(users, null, 2)}</pre>
</>
);
);
Example usage for returning multiple results with pagination:
const UserListComponent = () => {
const { data: users, loading, error, pagination } = useData<IAdminUser[]>('admin.User', {}, { paginate: { max: 1 } });
if (loading) {
return <div>Loading</div>;
}
if (error) {
return <div>{error.message}</div>;
}
return (
<>
<div>{1 + (pagination?.offset || 0)}/{pagination?.totalCount}</div>
<div>
<button disabled={!pagination?.hasPreviousPage} onClick={() => pagination?.previous()}>Previous</button>
<button disabled={!pagination?.hasNextPage} onClick={() => pagination?.next()}>Next</button>
</div>
<pre style={{padding: '10px'}}>{JSON.stringify(users, null, 2)}</pre>
</>
);
);
Explicitly turning off caching:
const UserComponent = () => {
const { data: user, loading, error } = useData<IAdminUser>('admin.User', 'ab980e7028c8b147', { cache: false });
if (loading) {
return <div>Loading</div>;
}
if (error) {
return <div>{error.message}</div>;
}
return (
<div>{user?.profile.first_name} {user?.profile.last_name}</div>
);
};
Setup the data but fetch later dynamically (or change the props dynamically):
const UserComponent = () => {
const { data: user, loading, pending, error, setID } = useData<IAdminUser>('admin.User');
if (loading) {
return <div>Loading</div>;
}
if (pending) {
return <button onClick={() => setID('ab980e7028c8b147')}>Click to load</button>;
}
if (error) {
return <div>{error.message}</div>;
}
return (
<div>{user?.profile.first_name} {user?.profile.last_name}</div>
);
};
Setup the data but fetch later dynamically using a callback function or Promise:
const UserComponent = () => {
const { data: user, loading, pending, error, setID } = useData<IAdminUser>('admin.User', () => {
return getGetSomeID(); // this can either return a promise or an immediate value
});
if (loading || pending) {
return <div>Loading</div>;
}
if (error) {
return <div>{error.message}</div>;
}
return (
<div>{user?.profile.first_name} {user?.profile.last_name}</div>
);
};
Create a dependency chain between different data and use dependencies to react to changes:
const DependencyComponent = () => {
const { data: customer, current: currentCustomer } = useData<IAdminCustomer[]>('admin.Customer', {});
const { data: subscription } = useData<IAdminCustomerSubscription>('admin.CustomerSubscription', () => {
// use current to get the captured current value which can be used outside the render
// since if you captured customer it would always be undefined when calling this function
// because it would have captured the closure value for the JS value but once the render
// function runs, the variable is out of scope and no longer valid. this current variable
// returned from useData will give you a function that you can invoke to get the current
// value of the data variable that was correctly captured during the previous render
const customer = currentCustomer();
if (customer) {
return {
filters: ['customer_id = ?'],
params: [customer[0]._id],
}
}
}, [customer]);
return (
<>
<div>Customer</div>
<pre style={{padding: '10px', color: 'orange'}}>{JSON.stringify(customer, null, 2)}</pre>
<div>Customer Subscription</div>
<pre style={{padding: '10px', color: 'yellow'}}>{JSON.stringify(subscription, null, 2)}</pre>
</>
);
};
All code is Copyright (c) 2020 by Pinpoint Software, Inc. and proprietary. Do not redistribute.
FAQs
A data manager for React apps inside Pinpoint
The npm package @pinpt/data-manager receives a total of 0 weekly downloads. As such, @pinpt/data-manager popularity was classified as not popular.
We found that @pinpt/data-manager demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 6 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.

Research
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.

Research
Malicious versions of the Telnyx Python SDK on PyPI delivered credential-stealing malware via a multi-stage supply chain attack.