@fluree/fluree-client
Advanced tools
Comparing version 1.0.5 to 1.0.6-beta1
@@ -6,2 +6,3 @@ import { IFlureeConfig } from '../interfaces/IFlureeConfig'; | ||
import { ContextStatement } from '../types/ContextTypes'; | ||
import { UpsertStatement } from '../types/TransactionTypes'; | ||
import { HistoryQueryInstance } from './HistoryQueryInstance'; | ||
@@ -131,2 +132,34 @@ import { QueryInstance } from './QueryInstance'; | ||
/** | ||
* Creates a new TransactionInstance for upserting with the Fluree database. The TransactionInstance can be used & re-used to build, sign, and send upsert transactions to the Fluree instance. | ||
* | ||
* Upsert is not an API endpoint in Fluree. This method helps to transform an upsert transaction into an insert/where/delete transaction. | ||
* | ||
* Upsert assumes that the facts provided in the transaction should be treated as the true & accurate state of the data after the transaction is processed. | ||
* | ||
* This means that facts in your transaction should be inserted (if new) and should replace existing facts (if they exist on those subjects & properties). | ||
* @param transaction {UpsertStatement} - The upsert transaction to send to the Fluree instance | ||
* @returns TransactionInstance | ||
* @example | ||
* // Existing data: | ||
* // [ | ||
* // { "@id": "freddy", "name": "Freddy" }, | ||
* // { "@id": "alice", "name": "Alice" } | ||
* // ] | ||
* | ||
* await client.upsert([ | ||
* { "@id": "freddy", "name": "Freddy the Yeti" }, | ||
* { "@id": "alice", "age": 25} | ||
* ]).send(); | ||
* | ||
* // New data state after txn: | ||
* // [ | ||
* // { "@id": "freddy", "name": "Freddy the Yeti" }, | ||
* // { "@id": "alice", "name": "Alice", "age": 25 } | ||
* // ] | ||
* | ||
* // Note that if this had been an "insert" freddy would now have two names. | ||
* // Note also that if this had been handled by deleting/insert, alice might have lost her name. | ||
*/ | ||
upsert(transaction: UpsertStatement): TransactionInstance; | ||
/** | ||
* Creates a new HistoryQueryInstance for querying the history of the Fluree database. The HistoryQueryInstance can be used & re-used to build, sign, and send history queries to the Fluree instance. | ||
@@ -133,0 +166,0 @@ * @param query {IFlureeHistoryQuery} - The history query to send to the Fluree instance |
@@ -20,2 +20,3 @@ "use strict"; | ||
const contextHandler_1 = require("../utils/contextHandler"); | ||
const transactionUtils_1 = require("../utils/transactionUtils"); | ||
const FlureeError_1 = require("./FlureeError"); | ||
@@ -201,2 +202,42 @@ const HistoryQueryInstance_1 = require("./HistoryQueryInstance"); | ||
/** | ||
* Creates a new TransactionInstance for upserting with the Fluree database. The TransactionInstance can be used & re-used to build, sign, and send upsert transactions to the Fluree instance. | ||
* | ||
* Upsert is not an API endpoint in Fluree. This method helps to transform an upsert transaction into an insert/where/delete transaction. | ||
* | ||
* Upsert assumes that the facts provided in the transaction should be treated as the true & accurate state of the data after the transaction is processed. | ||
* | ||
* This means that facts in your transaction should be inserted (if new) and should replace existing facts (if they exist on those subjects & properties). | ||
* @param transaction {UpsertStatement} - The upsert transaction to send to the Fluree instance | ||
* @returns TransactionInstance | ||
* @example | ||
* // Existing data: | ||
* // [ | ||
* // { "@id": "freddy", "name": "Freddy" }, | ||
* // { "@id": "alice", "name": "Alice" } | ||
* // ] | ||
* | ||
* await client.upsert([ | ||
* { "@id": "freddy", "name": "Freddy the Yeti" }, | ||
* { "@id": "alice", "age": 25} | ||
* ]).send(); | ||
* | ||
* // New data state after txn: | ||
* // [ | ||
* // { "@id": "freddy", "name": "Freddy the Yeti" }, | ||
* // { "@id": "alice", "name": "Alice", "age": 25 } | ||
* // ] | ||
* | ||
* // Note that if this had been an "insert" freddy would now have two names. | ||
* // Note also that if this had been handled by deleting/insert, alice might have lost her name. | ||
*/ | ||
upsert(transaction) { | ||
if (!this.connected) { | ||
throw new FlureeError_1.FlureeError('You must connect before transacting. Try using .connect().transact() instead'); | ||
} | ||
const idAlias = (0, contextHandler_1.findIdAlias)(this.config.defaultContext || {}); | ||
const resultTransaction = (0, transactionUtils_1.handleUpsert)(transaction, idAlias); | ||
resultTransaction.ledger = this.config.ledger; | ||
return new TransactionInstance_1.TransactionInstance(resultTransaction, this.config); | ||
} | ||
/** | ||
* Creates a new HistoryQueryInstance for querying the history of the Fluree database. The HistoryQueryInstance can be used & re-used to build, sign, and send history queries to the Fluree instance. | ||
@@ -456,8 +497,10 @@ * @param query {IFlureeHistoryQuery} - The history query to send to the Fluree instance | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return this.query({ | ||
const queryInstance = this.query({ | ||
where: { | ||
'@id': '?s', | ||
'?p': '?o', | ||
}, | ||
selectOne: ['?s'], | ||
}).send(); | ||
}); | ||
return queryInstance.send(); | ||
}); | ||
@@ -464,0 +507,0 @@ }, _FlureeClient_createLedger = function _FlureeClient_createLedger(ledgerName) { |
export declare class FlureeError extends Error { | ||
readonly code?: number | undefined; | ||
constructor(message: string, code?: number | undefined); | ||
statusCode?: number | undefined; | ||
statusText?: string | undefined; | ||
originalError?: any; | ||
constructor(message: string, statusCode?: number | undefined, statusText?: string | undefined, originalError?: any); | ||
} |
@@ -5,5 +5,9 @@ "use strict"; | ||
class FlureeError extends Error { | ||
constructor(message, code) { | ||
constructor(message, statusCode, statusText, | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
originalError) { | ||
super(message); | ||
this.code = code; | ||
this.statusCode = statusCode; | ||
this.statusText = statusText; | ||
this.originalError = originalError; | ||
this.name = 'FlureeError'; | ||
@@ -10,0 +14,0 @@ if (Error.captureStackTrace) { |
@@ -23,2 +23,3 @@ import { IFlureeConfig } from '../interfaces/IFlureeConfig'; | ||
config: IFlureeConfig; | ||
signedQuery: string; | ||
constructor(query: IFlureeHistoryQuery, config: IFlureeConfig); | ||
@@ -32,2 +33,48 @@ /** | ||
send(): Promise<any>; | ||
/** | ||
* Signs the history query with the provided privateKey (or the privateKey from the config if none is provided) | ||
* @param privateKey - (Optional) The private key to sign the history query with | ||
* @returns HistoryQueryInstance | ||
* @example | ||
* const signedHistoryQuery = historyQuery.sign(privateKey); | ||
* | ||
* // or | ||
* | ||
* const signedHistoryQuery = historyQuery.sign(); // if the privateKey is provided in the config | ||
*/ | ||
sign(privateKey?: string): HistoryQueryInstance; | ||
/** | ||
* Returns the signed history query as a JWS string (if the history query has been signed) | ||
* @returns string | ||
* @example | ||
* const signedHistoryQuery = historyQuery.sign(); | ||
* | ||
* const jwsString = historyQuery.getSignedQuery(); | ||
*/ | ||
getSignedQuery(): string; | ||
/** | ||
* Returns the fully-qualified history query object | ||
* @returns IFlureeHistoryQuery | ||
* @example | ||
* const client = await new FlureeClient({ | ||
* host: localhost, | ||
* port: 8080, | ||
* ledger: 'test/history-query', | ||
* }).connect(); | ||
* | ||
* const historyQuery = client | ||
* .history({ | ||
* 'commit-details': true, | ||
* t: { at: 'latest' }, | ||
* }) | ||
* const historyQueryObject = historyQuery.getQuery(); | ||
* | ||
* console.log(historyQueryObject); | ||
* // { | ||
* // 'commit-details': true, | ||
* // t: { at: 'latest' }, | ||
* // from: "test/history-query" | ||
* // } | ||
*/ | ||
getQuery(): IFlureeHistoryQuery; | ||
} |
@@ -13,2 +13,3 @@ "use strict"; | ||
exports.HistoryQueryInstance = void 0; | ||
const crypto_1 = require("@fluree/crypto"); | ||
const fetchOptions_1 = require("../utils/fetchOptions"); | ||
@@ -35,2 +36,3 @@ const FlureeError_1 = require("./FlureeError"); | ||
constructor(query, config) { | ||
this.signedQuery = ''; | ||
if (!query.history && !query['commit-details']) { | ||
@@ -41,2 +43,5 @@ throw new FlureeError_1.FlureeError('either the history or commit-details key is required'); | ||
this.config = config; | ||
if (config.signMessages) { | ||
this.sign(); | ||
} | ||
} | ||
@@ -51,9 +56,10 @@ /** | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const [url, fetchOptions] = (0, fetchOptions_1.generateFetchParams)(this.config, 'history'); | ||
fetchOptions.body = JSON.stringify(this.query); | ||
const contentType = (this.signedQuery && this.config.isFlureeHosted) ? "application/jwt" : "application/json"; | ||
const [url, fetchOptions] = (0, fetchOptions_1.generateFetchParams)(this.config, 'history', contentType); | ||
fetchOptions.body = this.signedQuery || JSON.stringify(this.query); | ||
return fetch(url, fetchOptions) | ||
.then((response) => { | ||
// if (response.status > 201) { | ||
// throw new Error(response.statusText); | ||
// } | ||
if (response.status > 201) { | ||
throw new FlureeError_1.FlureeError(response.statusText); | ||
} | ||
return response.json(); | ||
@@ -69,3 +75,65 @@ }) | ||
} | ||
/** | ||
* Signs the history query with the provided privateKey (or the privateKey from the config if none is provided) | ||
* @param privateKey - (Optional) The private key to sign the history query with | ||
* @returns HistoryQueryInstance | ||
* @example | ||
* const signedHistoryQuery = historyQuery.sign(privateKey); | ||
* | ||
* // or | ||
* | ||
* const signedHistoryQuery = historyQuery.sign(); // if the privateKey is provided in the config | ||
*/ | ||
sign(privateKey) { | ||
const key = privateKey !== null && privateKey !== void 0 ? privateKey : this.config.privateKey; | ||
if (!key) { | ||
throw new FlureeError_1.FlureeError('privateKey must be provided as either a function parameter or in the config'); | ||
} | ||
const signedHistoryQuery = JSON.stringify((0, crypto_1.createJWS)(JSON.stringify(this.query), key)); | ||
this.signedQuery = signedHistoryQuery; | ||
return this; | ||
} | ||
// setTime(time: string): QueryInstance { | ||
// this.query.t = time; | ||
// return this; | ||
// } | ||
/** | ||
* Returns the signed history query as a JWS string (if the history query has been signed) | ||
* @returns string | ||
* @example | ||
* const signedHistoryQuery = historyQuery.sign(); | ||
* | ||
* const jwsString = historyQuery.getSignedQuery(); | ||
*/ | ||
getSignedQuery() { | ||
return this.signedQuery; | ||
} | ||
/** | ||
* Returns the fully-qualified history query object | ||
* @returns IFlureeHistoryQuery | ||
* @example | ||
* const client = await new FlureeClient({ | ||
* host: localhost, | ||
* port: 8080, | ||
* ledger: 'test/history-query', | ||
* }).connect(); | ||
* | ||
* const historyQuery = client | ||
* .history({ | ||
* 'commit-details': true, | ||
* t: { at: 'latest' }, | ||
* }) | ||
* const historyQueryObject = historyQuery.getQuery(); | ||
* | ||
* console.log(historyQueryObject); | ||
* // { | ||
* // 'commit-details': true, | ||
* // t: { at: 'latest' }, | ||
* // from: "test/history-query" | ||
* // } | ||
*/ | ||
getQuery() { | ||
return this.query; | ||
} | ||
} | ||
exports.HistoryQueryInstance = HistoryQueryInstance; |
@@ -55,18 +55,23 @@ "use strict"; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const query = this.signedQuery || JSON.stringify(this.query); | ||
const [url, fetchOptions] = (0, fetchOptions_1.generateFetchParams)(this.config, 'query'); | ||
fetchOptions.body = query; | ||
return fetch(url, fetchOptions) | ||
.then((response) => { | ||
// if (response.status > 201) { | ||
// throw new Error(response.statusText); | ||
// } | ||
return response.json(); | ||
}) | ||
.then((json) => { | ||
if (json.error) { | ||
throw new FlureeError_1.FlureeError(`${json.error}: ${json.message}`); | ||
const contentType = this.signedQuery && this.config.isFlureeHosted | ||
? 'application/jwt' | ||
: 'application/json'; | ||
const [url, fetchOptions] = (0, fetchOptions_1.generateFetchParams)(this.config, 'query', contentType); | ||
fetchOptions.body = this.signedQuery || JSON.stringify(this.query); | ||
try { | ||
const response = yield fetch(url, fetchOptions); | ||
const json = yield response.json(); | ||
// Check for HTTP errors or application-specific errors in the JSON | ||
if (response.status > 201 || json.error) { | ||
throw new FlureeError_1.FlureeError(`Send Query Error: ${json.error ? json.error.message : response.statusText}`, response.status, response.statusText, json.error); | ||
} | ||
return json; | ||
}); | ||
} | ||
catch (error) { | ||
if (error instanceof FlureeError_1.FlureeError) { | ||
throw error; // Rethrow if it's already a FlureeError | ||
} | ||
// Wrap unknown errors in FlureeError | ||
throw new FlureeError_1.FlureeError('Unexpected error sending query', 0, '', error); | ||
} | ||
}); | ||
@@ -73,0 +78,0 @@ } |
@@ -55,18 +55,25 @@ "use strict"; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const transaction = this.signedTransaction || JSON.stringify(this.transaction); | ||
const [url, fetchOptions] = (0, fetchOptions_1.generateFetchParams)(this.config, 'transact'); | ||
fetchOptions.body = transaction; | ||
return fetch(url, fetchOptions) | ||
.then((response) => { | ||
// if (response.status > 201) { | ||
// throw new Error(response.statusText); | ||
// } | ||
return response.json(); | ||
}) | ||
.then((json) => { | ||
if (json.error) { | ||
throw new Error(`${json.error}: ${json.message}`); | ||
const contentType = this.signedTransaction && this.config.isFlureeHosted | ||
? 'application/jwt' | ||
: 'application/json'; | ||
const [url, fetchOptions] = (0, fetchOptions_1.generateFetchParams)(this.config, 'transact', contentType); | ||
fetchOptions.body = | ||
this.signedTransaction || JSON.stringify(this.transaction); | ||
try { | ||
const response = yield fetch(url, fetchOptions); | ||
const json = yield response.json(); | ||
// Check for HTTP errors or application-specific errors in the JSON | ||
if (response.status > 201 || json.error) { | ||
console.log(JSON.stringify(json, null, 2)); | ||
throw new FlureeError_1.FlureeError(`Send Transaction Error: ${json.error ? json.error.message : response.statusText}`, response.status, response.statusText, json.error); | ||
} | ||
return json; | ||
}); | ||
} | ||
catch (error) { | ||
if (error instanceof FlureeError_1.FlureeError) { | ||
throw error; // Rethrow if it's already a FlureeError | ||
} | ||
// Wrap unknown errors in FlureeError | ||
throw new FlureeError_1.FlureeError('Unexpected error sending transaction', 0, '', error); | ||
} | ||
}); | ||
@@ -73,0 +80,0 @@ } |
type InsertObject = { | ||
[key: string]: string | string[] | InsertStatement; | ||
[key: string]: string | string[] | number | number[] | boolean | boolean[] | InsertStatement; | ||
}; | ||
type InsertArray = Array<InsertObject>; | ||
export type InsertArray = Array<InsertObject>; | ||
type DeleteObject = { | ||
@@ -11,2 +11,3 @@ [key: string]: string | DeleteStatement; | ||
export type DeleteStatement = DeleteObject | DeleteArray; | ||
export type UpsertStatement = InsertStatement; | ||
export {}; |
@@ -9,1 +9,9 @@ import { ContextStatement } from '../types/ContextTypes'; | ||
export declare function mergeContexts(context1: ContextStatement, context2: ContextStatement): ContextStatement; | ||
/** | ||
* Find the alias for a given context. This includes searching through context arrays or nested context for any value of "@id" | ||
* For example, if the context is ["https://ns.flur.ee/", { "ex": "https://example.com/", "id": "@id" }] | ||
* Then "id" is serving as an alias for "@id" | ||
* @param context the context to search for an alias | ||
* @returns the alias for the context | ||
*/ | ||
export declare function findIdAlias(context: ContextStatement): string; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.mergeContexts = void 0; | ||
exports.findIdAlias = exports.mergeContexts = void 0; | ||
/** | ||
@@ -32,2 +32,4 @@ * | ||
else { | ||
if (Object.entries(context2).length === 0) | ||
return context1; | ||
return context1.concat([context2]); | ||
@@ -51,2 +53,31 @@ } | ||
exports.mergeContexts = mergeContexts; | ||
/** | ||
* Find the alias for a given context. This includes searching through context arrays or nested context for any value of "@id" | ||
* For example, if the context is ["https://ns.flur.ee/", { "ex": "https://example.com/", "id": "@id" }] | ||
* Then "id" is serving as an alias for "@id" | ||
* @param context the context to search for an alias | ||
* @returns the alias for the context | ||
*/ | ||
function findIdAlias(context) { | ||
if (typeof context === 'string') { | ||
return '@id'; | ||
} | ||
else if (Array.isArray(context)) { | ||
let result = '@id'; | ||
for (const item of context) { | ||
result = findIdAlias(item); | ||
} | ||
return result; | ||
} | ||
else { | ||
let result = '@id'; | ||
for (const key in context) { | ||
if (context[key] === '@id') { | ||
result = key; | ||
} | ||
} | ||
return result; | ||
} | ||
} | ||
exports.findIdAlias = findIdAlias; | ||
// /** | ||
@@ -53,0 +84,0 @@ // * Find the alias for a given context. This includes searching through context arrays or nested context for any value of "@context" |
import { IFlureeConfig } from '../interfaces/IFlureeConfig'; | ||
export declare const generateFetchParams: (config: IFlureeConfig, endpoint: string) => [string, { | ||
export declare const generateFetchParams: (config: IFlureeConfig, endpoint: string, contentType?: string) => [string, { | ||
method: string; | ||
@@ -4,0 +4,0 @@ headers: { |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.generateFetchParams = void 0; | ||
const generateFetchParams = (config, endpoint) => { | ||
const generateFetchParams = (config, endpoint, contentType = "application/json") => { | ||
const { host, port, isFlureeHosted, apiKey } = config; | ||
@@ -19,3 +19,3 @@ let url; | ||
const headers = { | ||
'Content-Type': 'application/json', | ||
'Content-Type': contentType, | ||
}; | ||
@@ -22,0 +22,0 @@ if (apiKey) { |
{ | ||
"name": "@fluree/fluree-client", | ||
"version": "1.0.5", | ||
"version": "1.0.6-beta1", | ||
"description": "", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
@@ -674,1 +674,16 @@ # Fluree Client SDK for TypeScript/JavaScript | ||
``` | ||
## Running tests | ||
Before running tests, you'll need a `.env.local` file in the root of the project. | ||
This file needs to contain the following: | ||
``` | ||
TEST_NEXUS_LEDGER="fluree-jld/387028092978318" | ||
TEST_API_KEY="_DPu2OWxmJ-zRwnzNr8uL...5mfV1OsfOXcRmb35t02rp1gMxxSw" | ||
``` | ||
### Run tests | ||
In the root of the project, run: | ||
``` | ||
yarn test | ||
``` |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
92770
38
1931
688
2