@dsnp/graph-sdk
Advanced tools
Comparing version 0.0.9 to 0.0.10
@@ -1,2 +0,2 @@ | ||
import { ImportBundle, Update, DsnpGraphEdge, Action, DsnpPublicKey, DsnpKeys, Config, ConnectionType, PrivacyType, GraphKeyPair } from "./models"; | ||
import { ImportBundle, Update, DsnpGraphEdge, Action, DsnpPublicKey, DsnpKeys, Config, ConnectionType, PrivacyType, GraphKeyPair, ActionOptions } from "./models"; | ||
import { EnvironmentInterface } from "./models/environment"; | ||
@@ -7,21 +7,22 @@ export declare class Graph { | ||
getGraphHandle(): number; | ||
getGraphConfig(environment: EnvironmentInterface): Promise<Config>; | ||
getSchemaIdFromConfig(environment: EnvironmentInterface, connectionType: ConnectionType, privacyType: PrivacyType): Promise<number>; | ||
getGraphStatesCount(): Promise<number>; | ||
containsUserGraph(dsnpUserId: string): Promise<boolean>; | ||
getGraphUsersCount(): Promise<number>; | ||
removeUserGraph(dsnpUserId: string): Promise<boolean>; | ||
importUserData(payload: ImportBundle[]): Promise<boolean>; | ||
exportUpdates(): Promise<Update[]>; | ||
getConnectionsForUserGraph(dsnpUserId: string, schemaId: number, includePending: boolean): Promise<DsnpGraphEdge[]>; | ||
applyActions(actions: Action[]): Promise<boolean>; | ||
forceCalculateGraphs(dsnpUserId: string): Promise<Update[]>; | ||
getConnectionsWithoutKeys(): Promise<string[]>; | ||
getOneSidedPrivateFriendshipConnections(dsnpUserId: string): Promise<DsnpGraphEdge[]>; | ||
getPublicKeys(dsnpUserId: string): Promise<DsnpPublicKey[]>; | ||
static deserializeDsnpKeys(keys: DsnpKeys): Promise<DsnpPublicKey[]>; | ||
static generateKeyPair(keyType: number): Promise<GraphKeyPair>; | ||
freeGraphState(): Promise<boolean>; | ||
getGraphConfig(environment: EnvironmentInterface): Config; | ||
getSchemaIdFromConfig(environment: EnvironmentInterface, connectionType: ConnectionType, privacyType: PrivacyType): number; | ||
getGraphStatesCount(): number; | ||
containsUserGraph(dsnpUserId: string): boolean; | ||
getGraphUsersCount(): number; | ||
removeUserGraph(dsnpUserId: string): boolean; | ||
importUserData(payload: ImportBundle[]): boolean; | ||
exportUpdates(): Update[]; | ||
exportUserGraphUpdates(dsnpUserId: string): Update[]; | ||
getConnectionsForUserGraph(dsnpUserId: string, schemaId: number, includePending: boolean): DsnpGraphEdge[]; | ||
applyActions(actions: Action[], options?: ActionOptions): boolean; | ||
forceCalculateGraphs(dsnpUserId: string): Update[]; | ||
getConnectionsWithoutKeys(): string[]; | ||
getOneSidedPrivateFriendshipConnections(dsnpUserId: string): DsnpGraphEdge[]; | ||
getPublicKeys(dsnpUserId: string): DsnpPublicKey[]; | ||
static deserializeDsnpKeys(keys: DsnpKeys): DsnpPublicKey[]; | ||
static generateKeyPair(keyType: number): GraphKeyPair; | ||
freeGraphState(): boolean; | ||
printHelloGraph(): void; | ||
} | ||
//# sourceMappingURL=graph.d.ts.map |
@@ -36,6 +36,12 @@ "use strict"; | ||
} | ||
exportUserGraphUpdates(dsnpUserId) { | ||
return index_1.graphsdkModule.exportUserGraphUpdates(this.handle, dsnpUserId); | ||
} | ||
getConnectionsForUserGraph(dsnpUserId, schemaId, includePending) { | ||
return index_1.graphsdkModule.getConnectionsForUserGraph(this.handle, dsnpUserId, schemaId, includePending); | ||
} | ||
applyActions(actions) { | ||
applyActions(actions, options) { | ||
if (options) { | ||
return index_1.graphsdkModule.applyActions(this.handle, actions, options); | ||
} | ||
return index_1.graphsdkModule.applyActions(this.handle, actions); | ||
@@ -42,0 +48,0 @@ } |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const graph_1 = require("./graph"); | ||
const import_bundle_builder_1 = require("./import-bundle-builder"); | ||
const models_1 = require("./models"); | ||
const config_1 = require("./models/config"); | ||
const environment_1 = require("./models/environment"); | ||
function getTestConfig() { | ||
const config = {}; | ||
config.sdkMaxStaleFriendshipDays = 100; | ||
config.maxPageId = 100; | ||
config.dsnpVersions = [config_1.DsnpVersion.Version1_0]; | ||
config.maxGraphPageSizeBytes = 100; | ||
config.maxKeyPageSizeBytes = 100; | ||
const schemaConfig = {}; | ||
schemaConfig.dsnpVersion = config_1.DsnpVersion.Version1_0; | ||
schemaConfig.connectionType = config_1.ConnectionType.Follow; | ||
schemaConfig.privacyType = config_1.PrivacyType.Public; | ||
config.schemaMap = { 1: schemaConfig }; | ||
config.graphPublicKeySchemaId = 11; | ||
return config; | ||
} | ||
test('printHelloGraph should print "Hello, Graph!"', async () => { | ||
// Mock the console.log function | ||
const consoleLogMock = jest.spyOn(console, 'log').mockImplementation(); | ||
const environment = { environmentType: environment_1.EnvironmentType.Mainnet }; | ||
const graph = new graph_1.Graph(environment); | ||
await graph.printHelloGraph(); | ||
expect(consoleLogMock).toHaveBeenCalledWith('Hello, Graph!'); | ||
await graph.freeGraphState(); | ||
}); | ||
test('getGraphConfig should return the graph config', async () => { | ||
const config_input = getTestConfig(); | ||
const environment = { environmentType: environment_1.EnvironmentType.Dev, config: config_input }; | ||
const graph = new graph_1.Graph(environment); | ||
const config = await graph.getGraphConfig(environment); | ||
expect(config).toBeDefined(); | ||
expect(config.graphPublicKeySchemaId).toEqual(11); | ||
await graph.freeGraphState(); | ||
}); | ||
test('getGraphConfig with Mainnet environment should return the graph config', async () => { | ||
const environment = { environmentType: environment_1.EnvironmentType.Mainnet }; | ||
const graph = new graph_1.Graph(environment); | ||
const config = await graph.getGraphConfig(environment); | ||
expect(config).toBeDefined(); | ||
expect(config.graphPublicKeySchemaId).toEqual(5); | ||
const schema_id = await graph.getSchemaIdFromConfig(environment, config_1.ConnectionType.Follow, config_1.PrivacyType.Public); | ||
expect(schema_id).toEqual(1); | ||
await graph.freeGraphState(); | ||
}); | ||
test('getGraphConfig with Rococo environment should return the graph config', async () => { | ||
const environment = { environmentType: environment_1.EnvironmentType.Rococo }; | ||
const graph = new graph_1.Graph(environment); | ||
const config = await graph.getGraphConfig(environment); | ||
expect(config).toBeDefined(); | ||
await graph.freeGraphState(); | ||
}); | ||
test('getGraphStatesCount should be zero after previous graph is freed', async () => { | ||
const config = getTestConfig(); | ||
const environment = { environmentType: environment_1.EnvironmentType.Dev, config }; | ||
const graph = new graph_1.Graph(environment); | ||
const handle = graph.getGraphHandle(); | ||
expect(handle).toBeDefined(); | ||
await graph.freeGraphState(); | ||
const count = await graph.getGraphStatesCount(); | ||
expect(count).toEqual(0); | ||
}); | ||
test('getGraphStatesCount should be one after graph is initialized', async () => { | ||
const config = getTestConfig(); | ||
const environment = { environmentType: environment_1.EnvironmentType.Dev, config }; | ||
const graph = new graph_1.Graph(environment); | ||
const handle = graph.getGraphHandle(); | ||
expect(handle).toBeDefined(); | ||
const count = await graph.getGraphStatesCount(); | ||
expect(count).toEqual(1); | ||
await graph.freeGraphState(); | ||
}); | ||
test('getGraphUsersCount should be zero on initialized graph', async () => { | ||
const config = getTestConfig(); | ||
const environment = { environmentType: environment_1.EnvironmentType.Dev, config }; | ||
const graph = new graph_1.Graph(environment); | ||
const handle = graph.getGraphHandle(); | ||
expect(handle).toBeDefined(); | ||
const count = await graph.getGraphUsersCount(); | ||
expect(count).toEqual(0); | ||
await graph.freeGraphState(); | ||
await expect(async () => { | ||
await graph.getGraphUsersCount(); | ||
}).rejects.toThrow('Graph state not found'); | ||
}); | ||
test('containsUserGraph should return false on initialized graph', async () => { | ||
const config = getTestConfig(); | ||
const environment = { environmentType: environment_1.EnvironmentType.Dev, config }; | ||
const graph = new graph_1.Graph(environment); | ||
const handle = graph.getGraphHandle(); | ||
expect(handle).toBeDefined(); | ||
const contains = await graph.containsUserGraph("1"); | ||
expect(contains).toEqual(false); | ||
await graph.freeGraphState(); | ||
}); | ||
test('removeUserGraph should pass through on initialized graph', async () => { | ||
const config = getTestConfig(); | ||
const environment = { environmentType: environment_1.EnvironmentType.Dev, config }; | ||
const graph = new graph_1.Graph(environment); | ||
const handle = graph.getGraphHandle(); | ||
expect(handle).toBeDefined(); | ||
const removed = await graph.removeUserGraph("1"); | ||
expect(removed).toEqual(true); | ||
await graph.freeGraphState(); | ||
}); | ||
test('importUserData should pass through on initialized graph', async () => { | ||
const environment = { environmentType: environment_1.EnvironmentType.Mainnet }; | ||
const graph = new graph_1.Graph(environment); | ||
const handle = graph.getGraphHandle(); | ||
expect(handle).toBeDefined(); | ||
// Set up import data | ||
const dsnpUserId1 = 1; | ||
const dsnpUserId2 = 2; | ||
const pageData1 = { | ||
pageId: 1, | ||
content: new Uint8Array([24, 227, 96, 97, 96, 99, 224, 96, 224, 98, 96, 0, 0]), | ||
contentHash: 100, | ||
}; | ||
const keyPairs1 = []; | ||
const keyPairs2 = []; | ||
const dsnpKeys1 = { | ||
dsnpUserId: dsnpUserId1.toString(), | ||
keysHash: 100, | ||
keys: [], | ||
}; | ||
const dsnpKeys2 = { | ||
dsnpUserId: dsnpUserId2.toString(), | ||
keysHash: 100, | ||
keys: [], | ||
}; | ||
const importBundle1 = { | ||
dsnpUserId: dsnpUserId1.toString(), | ||
schemaId: 1, | ||
keyPairs: keyPairs1, | ||
dsnpKeys: dsnpKeys1, | ||
pages: [pageData1], | ||
}; | ||
const importBundle2 = { | ||
dsnpUserId: dsnpUserId2.toString(), | ||
schemaId: 1, | ||
keyPairs: keyPairs2, | ||
dsnpKeys: dsnpKeys2, | ||
pages: [pageData1], | ||
}; | ||
// Import user data for each ImportBundle | ||
const imported = await graph.importUserData([importBundle1, importBundle2]); | ||
expect(imported).toEqual(true); | ||
await graph.freeGraphState(); | ||
}); | ||
test('applyActions with empty actions should pass through on initialized graph', async () => { | ||
const environment = { environmentType: environment_1.EnvironmentType.Mainnet }; | ||
const graph = new graph_1.Graph(environment); | ||
const handle = graph.getGraphHandle(); | ||
expect(handle).toBeDefined(); | ||
// Set up actions | ||
const actions = []; | ||
const applied = await graph.applyActions(actions); | ||
expect(applied).toEqual(true); | ||
await graph.freeGraphState(); | ||
}); | ||
test('applyActions with few actions should pass through on initialized graph', async () => { | ||
const config = getTestConfig(); | ||
const environment = { environmentType: environment_1.EnvironmentType.Dev, config }; | ||
const graph = new graph_1.Graph(environment); | ||
const handle = graph.getGraphHandle(); | ||
expect(handle).toBeDefined(); | ||
// Set up actions | ||
const actions = []; | ||
const action_1 = { | ||
type: "Connect", | ||
ownerDsnpUserId: "1", | ||
connection: { | ||
dsnpUserId: "2", | ||
schemaId: 1, | ||
const config = { | ||
sdkMaxStaleFriendshipDays: 100, | ||
maxPageId: 100, | ||
dsnpVersions: [config_1.DsnpVersion.Version1_0], | ||
maxGraphPageSizeBytes: 100, | ||
maxKeyPageSizeBytes: 100, | ||
schemaMap: { | ||
1: { | ||
dsnpVersion: config_1.DsnpVersion.Version1_0, | ||
connectionType: config_1.ConnectionType.Follow, | ||
privacyType: config_1.PrivacyType.Public, | ||
}, | ||
// dsnpKeys: { | ||
// dsnpUserId: "2", | ||
// keysHash: 100, | ||
// keys: [], | ||
// } as DsnpKeys, | ||
}; | ||
actions.push(action_1); | ||
const applied = await graph.applyActions(actions); | ||
expect(applied).toEqual(true); | ||
const exported = await graph.exportUpdates(); | ||
expect(exported).toBeDefined(); | ||
expect(exported.length).toEqual(1); | ||
await graph.freeGraphState(); | ||
}); | ||
test('getConnectionsForUserGraph with empty connections should return empty array', async () => { | ||
const config = getTestConfig(); | ||
const environment = { environmentType: environment_1.EnvironmentType.Dev, config }; | ||
const graph = new graph_1.Graph(environment); | ||
const handle = graph.getGraphHandle(); | ||
expect(handle).toBeDefined(); | ||
// Set up actions | ||
const actions = []; | ||
const action_1 = { | ||
type: "Connect", | ||
ownerDsnpUserId: "1", | ||
connection: { | ||
dsnpUserId: "2", | ||
schemaId: 1, | ||
2: { | ||
dsnpVersion: config_1.DsnpVersion.Version1_0, | ||
connectionType: config_1.ConnectionType.Follow, | ||
privacyType: config_1.PrivacyType.Private, | ||
}, | ||
dsnpKeys: { | ||
dsnpUserId: "2", | ||
3: { | ||
dsnpVersion: config_1.DsnpVersion.Version1_0, | ||
connectionType: config_1.ConnectionType.Friendship, | ||
privacyType: config_1.PrivacyType.Private, | ||
}, | ||
}, | ||
graphPublicKeySchemaId: 11, | ||
}; | ||
const environment = { | ||
environmentType: environment_1.EnvironmentType.Dev, | ||
config, | ||
}; | ||
describe("Graph tests", () => { | ||
let graph; | ||
let handle; | ||
beforeEach(() => { | ||
graph = new graph_1.Graph(environment); | ||
handle = graph.getGraphHandle(); | ||
expect(handle).toBeDefined(); | ||
}); | ||
afterEach(() => { | ||
graph.freeGraphState(); | ||
}); | ||
test('printHelloGraph should print "Hello, Graph!"', async () => { | ||
// Mock the console.log function | ||
const consoleLogMock = jest.spyOn(console, "log").mockImplementation(); | ||
graph.printHelloGraph(); | ||
expect(consoleLogMock).toHaveBeenCalledWith("Hello, Graph!"); | ||
}); | ||
test("getGraphConfig should return the graph config", async () => { | ||
const config_ret = graph.getGraphConfig(environment); | ||
expect(config_ret).toBeDefined(); | ||
expect(config_ret.graphPublicKeySchemaId).toEqual(11); | ||
}); | ||
test("getGraphConfig with Mainnet environment should return the graph config", async () => { | ||
const environment = { | ||
environmentType: environment_1.EnvironmentType.Mainnet, | ||
}; | ||
const graph = new graph_1.Graph(environment); | ||
const config = graph.getGraphConfig(environment); | ||
expect(config).toBeDefined(); | ||
expect(config.graphPublicKeySchemaId).toEqual(5); | ||
const schema_id = graph.getSchemaIdFromConfig(environment, config_1.ConnectionType.Follow, config_1.PrivacyType.Public); | ||
expect(schema_id).toEqual(1); | ||
graph.freeGraphState(); | ||
}); | ||
test("getGraphConfig with Rococo environment should return the graph config", async () => { | ||
const environment = { | ||
environmentType: environment_1.EnvironmentType.Rococo, | ||
}; | ||
const graph = new graph_1.Graph(environment); | ||
const config = graph.getGraphConfig(environment); | ||
expect(config).toBeDefined(); | ||
graph.freeGraphState(); | ||
}); | ||
test("getGraphStatesCount should be unchanged after create/free new graph", async () => { | ||
const originalCount = graph.getGraphStatesCount(); | ||
const secondGraph = new graph_1.Graph(environment); | ||
secondGraph.freeGraphState(); | ||
expect(secondGraph.getGraphStatesCount()).toEqual(originalCount); | ||
}); | ||
test("getGraphStatesCount should be one after graph is initialized", async () => { | ||
const count = graph.getGraphStatesCount(); | ||
expect(count).toEqual(1); | ||
}); | ||
test("getGraphUsersCount should be zero on initialized graph", async () => { | ||
const count = graph.getGraphUsersCount(); | ||
expect(count).toEqual(0); | ||
}); | ||
test("containsUserGraph should return false on initialized graph", async () => { | ||
const contains = graph.containsUserGraph("1"); | ||
expect(contains).toEqual(false); | ||
}); | ||
test("removeUserGraph should pass through on initialized graph", async () => { | ||
const removed = graph.removeUserGraph("1"); | ||
expect(removed).toEqual(true); | ||
}); | ||
test("importUserData should pass through on initialized graph", async () => { | ||
// Set up import data | ||
const dsnpUserId1 = 1; | ||
const dsnpUserId2 = 2; | ||
const pageData1 = { | ||
pageId: 1, | ||
content: new Uint8Array([ | ||
24, 227, 96, 97, 96, 99, 224, 96, 224, 98, 96, 0, 0, | ||
]), | ||
contentHash: 100, | ||
}; | ||
const keyPairs1 = []; | ||
const keyPairs2 = []; | ||
const dsnpKeys1 = { | ||
dsnpUserId: dsnpUserId1.toString(), | ||
keysHash: 100, | ||
keys: [], | ||
}, | ||
}; | ||
actions.push(action_1); | ||
const applied = await graph.applyActions(actions); | ||
expect(applied).toEqual(true); | ||
const connections = await graph.getConnectionsForUserGraph("1", 1, true); | ||
expect(connections).toBeDefined(); | ||
expect(connections.length).toEqual(1); | ||
const forceCalculateGraphs = await graph.forceCalculateGraphs("1"); | ||
expect(forceCalculateGraphs).toBeDefined(); | ||
expect(forceCalculateGraphs.length).toEqual(0); | ||
await graph.freeGraphState(); | ||
}); | ||
test('getConnectionsWithoutKeys with empty connections should return empty array', async () => { | ||
const environment = { environmentType: environment_1.EnvironmentType.Mainnet }; | ||
const graph = new graph_1.Graph(environment); | ||
const handle = graph.getGraphHandle(); | ||
expect(handle).toBeDefined(); | ||
const connections = await graph.getConnectionsWithoutKeys(); | ||
expect(connections).toBeDefined(); | ||
expect(connections.length).toEqual(0); | ||
expect(async () => { | ||
await graph.getOneSidedPrivateFriendshipConnections("1"); | ||
}).rejects.toThrow('User graph for 1 is not imported'); | ||
await graph.freeGraphState(); | ||
}); | ||
test('getPublicKeys with empty connections should return empty array', async () => { | ||
const environment = { environmentType: environment_1.EnvironmentType.Mainnet }; | ||
const graph = new graph_1.Graph(environment); | ||
const handle = graph.getGraphHandle(); | ||
expect(handle).toBeDefined(); | ||
const keys = await graph.getPublicKeys("1"); | ||
expect(keys).toBeDefined(); | ||
expect(keys.length).toEqual(0); | ||
await graph.freeGraphState(); | ||
}); | ||
test('deserializeDsnpKeys with empty keys should return empty array', async () => { | ||
const environment = { environmentType: environment_1.EnvironmentType.Mainnet }; | ||
const graph = new graph_1.Graph(environment); | ||
const handle = graph.getGraphHandle(); | ||
expect(handle).toBeDefined(); | ||
const keys = { | ||
dsnpUserId: "2", | ||
keysHash: 100, | ||
keys: [], | ||
}; | ||
const des_keys = await graph_1.Graph.deserializeDsnpKeys(keys); | ||
expect(des_keys).toBeDefined(); | ||
expect(des_keys.length).toEqual(0); | ||
await graph.freeGraphState(); | ||
}); | ||
test('Create and export a new graph', async () => { | ||
const mainnet_environment = { environmentType: environment_1.EnvironmentType.Mainnet }; | ||
const graph = new graph_1.Graph(mainnet_environment); | ||
const public_follow_graph_schema_id = await graph.getSchemaIdFromConfig(mainnet_environment, config_1.ConnectionType.Follow, config_1.PrivacyType.Public); | ||
const connect_action = { | ||
type: "Connect", | ||
ownerDsnpUserId: "1", | ||
connection: { | ||
}; | ||
const dsnpKeys2 = { | ||
dsnpUserId: dsnpUserId2.toString(), | ||
keysHash: 100, | ||
keys: [], | ||
}; | ||
const importBundle1 = { | ||
dsnpUserId: dsnpUserId1.toString(), | ||
schemaId: 1, | ||
keyPairs: keyPairs1, | ||
dsnpKeys: dsnpKeys1, | ||
pages: [pageData1], | ||
}; | ||
const importBundle2 = { | ||
dsnpUserId: dsnpUserId2.toString(), | ||
schemaId: 1, | ||
keyPairs: keyPairs2, | ||
dsnpKeys: dsnpKeys2, | ||
pages: [pageData1], | ||
}; | ||
// Import user data for each ImportBundle | ||
const imported = graph.importUserData([importBundle1, importBundle2]); | ||
expect(imported).toEqual(true); | ||
}); | ||
test("applyActions with empty actions should pass through on initialized graph", async () => { | ||
// Set up actions | ||
const actions = []; | ||
const applied = graph.applyActions(actions); | ||
expect(applied).toEqual(true); | ||
}); | ||
test("applyActions with some actions should pass through on initialized graph", async () => { | ||
// Set up actions | ||
const actions = []; | ||
const action_1 = { | ||
type: "Connect", | ||
ownerDsnpUserId: "1", | ||
connection: { | ||
dsnpUserId: "2", | ||
schemaId: 1, | ||
}, | ||
}; | ||
actions.push(action_1); | ||
const applied = graph.applyActions(actions); | ||
expect(applied).toEqual(true); | ||
const exported = graph.exportUpdates(); | ||
expect(exported).toBeDefined(); | ||
expect(exported.length).toEqual(1); | ||
}); | ||
test("applyActions with options should honor options", async () => { | ||
// Add some connections to 2 empty graphs | ||
const dsnpId_1 = "1"; | ||
const dsnpId_2 = "2"; | ||
const schemaId = 1; | ||
let actions = [ | ||
{ | ||
type: "Connect", | ||
ownerDsnpUserId: dsnpId_1, | ||
connection: { | ||
dsnpUserId: dsnpId_2, | ||
schemaId, | ||
}, | ||
}, | ||
{ | ||
type: "Connect", | ||
ownerDsnpUserId: dsnpId_2, | ||
connection: { | ||
dsnpUserId: dsnpId_1, | ||
schemaId, | ||
}, | ||
}, | ||
]; | ||
graph.applyActions(actions); | ||
const exports = graph.exportUpdates(); | ||
const imports = exports | ||
.filter((update) => update.type === "PersistPage") | ||
.map((update) => { | ||
const persist = update; | ||
const builder = new import_bundle_builder_1.ImportBundleBuilder() | ||
.withDsnpUserId(persist.ownerDsnpUserId) | ||
.withSchemaId(persist.schemaId) | ||
.withPageData(persist.pageId, persist.payload, 1000); | ||
return builder.build(); | ||
}); | ||
graph.importUserData(imports); | ||
// Now we have graphs with connections, attempt to add redundant connection | ||
actions = [ | ||
{ | ||
type: "Connect", | ||
ownerDsnpUserId: dsnpId_1, | ||
connection: { | ||
dsnpUserId: dsnpId_2, | ||
schemaId, | ||
}, | ||
}, | ||
]; | ||
expect(() => graph.applyActions(actions)).toThrow(); | ||
expect(() => graph.applyActions(actions, { ignoreExistingConnections: true })).not.toThrow(); | ||
// Now try to remove a non-existent connection | ||
actions = [ | ||
{ | ||
type: "Disconnect", | ||
ownerDsnpUserId: dsnpId_1, | ||
connection: { | ||
dsnpUserId: "999", | ||
schemaId, | ||
}, | ||
}, | ||
]; | ||
expect(() => graph.applyActions(actions)).toThrow(); | ||
expect(() => graph.applyActions(actions, { ignoreMissingConnections: true })).not.toThrow(); | ||
}); | ||
test("getConnectionsForUserGraph with empty connections should return empty array", async () => { | ||
// Set up actions | ||
const actions = []; | ||
const action_1 = { | ||
type: "Connect", | ||
ownerDsnpUserId: "1", | ||
connection: { | ||
dsnpUserId: "2", | ||
schemaId: 1, | ||
}, | ||
dsnpKeys: { | ||
dsnpUserId: "2", | ||
keysHash: 100, | ||
keys: [], | ||
}, | ||
}; | ||
actions.push(action_1); | ||
const applied = graph.applyActions(actions); | ||
expect(applied).toEqual(true); | ||
const connections = graph.getConnectionsForUserGraph("1", 1, true); | ||
expect(connections).toBeDefined(); | ||
expect(connections.length).toEqual(1); | ||
const forceCalculateGraphs = graph.forceCalculateGraphs("1"); | ||
expect(forceCalculateGraphs).toBeDefined(); | ||
expect(forceCalculateGraphs.length).toEqual(0); | ||
}); | ||
test("getConnectionsWithoutKeys with empty connections should return empty array", async () => { | ||
const connections = graph.getConnectionsWithoutKeys(); | ||
expect(connections).toBeDefined(); | ||
expect(connections.length).toEqual(0); | ||
expect(() => graph.getOneSidedPrivateFriendshipConnections("1")).toThrow("User graph for 1 is not imported"); | ||
}); | ||
test("getPublicKeys with empty connections should return empty array", async () => { | ||
const keys = graph.getPublicKeys("1"); | ||
expect(keys).toBeDefined(); | ||
expect(keys.length).toEqual(0); | ||
}); | ||
test("deserializeDsnpKeys with empty keys should return empty array", async () => { | ||
const keys = { | ||
dsnpUserId: "2", | ||
schemaId: public_follow_graph_schema_id, | ||
}, | ||
dsnpKeys: { | ||
dsnpUserId: "2", | ||
keysHash: 100, | ||
keys: [], | ||
}, | ||
}; | ||
const actions = []; | ||
actions.push(connect_action); | ||
const applied = await graph.applyActions(actions); | ||
expect(applied).toEqual(true); | ||
const connections_including_pending = await graph.getConnectionsForUserGraph("1", public_follow_graph_schema_id, true); | ||
expect(connections_including_pending).toBeDefined(); | ||
expect(connections_including_pending.length).toEqual(1); | ||
const exported = await graph.exportUpdates(); | ||
expect(exported).toBeDefined(); | ||
expect(exported.length).toEqual(1); | ||
}); | ||
test('Add a new graph key', async () => { | ||
const environment = { environmentType: environment_1.EnvironmentType.Mainnet }; | ||
const graph = new graph_1.Graph(environment); | ||
const dsnpOwnerId = 1; | ||
const x25519_public_key = [ | ||
15, 234, 44, 175, 171, 220, 131, 117, 43, 227, 111, 165, 52, 150, 64, 218, 44, 130, 138, | ||
221, 10, 41, 13, 241, 60, 210, 216, 23, 62, 178, 73, 111, | ||
]; | ||
const addGraphKeyAction = { | ||
type: "AddGraphKey", | ||
ownerDsnpUserId: dsnpOwnerId.toString(), | ||
newPublicKey: new Uint8Array(x25519_public_key), | ||
}; | ||
const actions = []; | ||
actions.push(addGraphKeyAction); | ||
const applied = await graph.applyActions(actions); | ||
expect(applied).toEqual(true); | ||
const exported = await graph.exportUpdates(); | ||
expect(exported).toBeDefined(); | ||
expect(exported.length).toEqual(1); | ||
}); | ||
test('Read and deserialize published graph keys', async () => { | ||
const dsnp_key_owner = 1000; | ||
// published keys blobs fetched from blockchain | ||
const published_keys_blob = [ | ||
64, 15, 234, 44, 175, 171, 220, 131, 117, 43, 227, 111, 165, 52, 150, 64, 218, 44, 130, | ||
138, 221, 10, 41, 13, 241, 60, 210, 216, 23, 62, 178, 73, 111, | ||
]; | ||
const dsnp_keys = { | ||
dsnpUserId: dsnp_key_owner.toString(), | ||
keysHash: 100, | ||
keys: [ | ||
}; | ||
const des_keys = graph_1.Graph.deserializeDsnpKeys(keys); | ||
expect(des_keys).toBeDefined(); | ||
expect(des_keys.length).toEqual(0); | ||
}); | ||
test("Create and export a new graph", async () => { | ||
const public_follow_graph_schema_id = graph.getSchemaIdFromConfig(environment, config_1.ConnectionType.Follow, config_1.PrivacyType.Public); | ||
const connect_action = { | ||
type: "Connect", | ||
ownerDsnpUserId: "1", | ||
connection: { | ||
dsnpUserId: "2", | ||
schemaId: public_follow_graph_schema_id, | ||
}, | ||
dsnpKeys: { | ||
dsnpUserId: "2", | ||
keysHash: 100, | ||
keys: [], | ||
}, | ||
}; | ||
const actions = []; | ||
actions.push(connect_action); | ||
const applied = graph.applyActions(actions); | ||
expect(applied).toEqual(true); | ||
const connections_including_pending = graph.getConnectionsForUserGraph("1", public_follow_graph_schema_id, true); | ||
expect(connections_including_pending).toBeDefined(); | ||
expect(connections_including_pending.length).toEqual(1); | ||
const exported = graph.exportUpdates(); | ||
expect(exported).toBeDefined(); | ||
expect(exported.length).toEqual(1); | ||
}); | ||
test("Test exportGraph all-user and single-user variants", async () => { | ||
const publicFollowGraphSchemaId = graph.getSchemaIdFromConfig(environment, config_1.ConnectionType.Follow, config_1.PrivacyType.Public); | ||
const actions = [ | ||
{ | ||
index: 0, | ||
content: new Uint8Array(published_keys_blob), | ||
} | ||
], | ||
}; | ||
const deserialized_keys = await graph_1.Graph.deserializeDsnpKeys(dsnp_keys); | ||
expect(deserialized_keys).toBeDefined(); | ||
type: "Connect", | ||
ownerDsnpUserId: "1", | ||
connection: { | ||
dsnpUserId: "2", | ||
schemaId: publicFollowGraphSchemaId, | ||
}, | ||
}, | ||
{ | ||
type: "Connect", | ||
ownerDsnpUserId: "2", | ||
connection: { | ||
dsnpUserId: "1", | ||
schemaId: publicFollowGraphSchemaId, | ||
}, | ||
}, | ||
]; | ||
const applied = graph.applyActions(actions); | ||
expect(applied).toEqual(true); | ||
// Check that exportUpdates exports all users | ||
let exported = graph.exportUpdates(); | ||
expect(exported).toBeDefined(); | ||
expect(exported.length).toEqual(2); | ||
expect(exported.every((bundle) => ["1", "2"].some((user) => user === bundle.ownerDsnpUserId))); | ||
// Check that single-user export contains only that user | ||
exported = graph.exportUserGraphUpdates("1"); | ||
expect(exported).toBeDefined(); | ||
expect(exported.length).toEqual(1); | ||
expect(exported.every((bundle) => bundle.ownerDsnpUserId === "1")); | ||
}); | ||
test("Add a new graph key", async () => { | ||
const dsnpOwnerId = 1; | ||
const x25519_public_key = [ | ||
15, 234, 44, 175, 171, 220, 131, 117, 43, 227, 111, 165, 52, 150, 64, 218, | ||
44, 130, 138, 221, 10, 41, 13, 241, 60, 210, 216, 23, 62, 178, 73, 111, | ||
]; | ||
const addGraphKeyAction = { | ||
type: "AddGraphKey", | ||
ownerDsnpUserId: dsnpOwnerId.toString(), | ||
newPublicKey: new Uint8Array(x25519_public_key), | ||
}; | ||
const actions = []; | ||
actions.push(addGraphKeyAction); | ||
const applied = graph.applyActions(actions); | ||
expect(applied).toEqual(true); | ||
const exported = graph.exportUpdates(); | ||
expect(exported).toBeDefined(); | ||
expect(exported.length).toEqual(1); | ||
}); | ||
test("Read and deserialize published graph keys", async () => { | ||
const dsnp_key_owner = 1000; | ||
// published keys blobs fetched from blockchain | ||
const published_keys_blob = [ | ||
64, 15, 234, 44, 175, 171, 220, 131, 117, 43, 227, 111, 165, 52, 150, 64, | ||
218, 44, 130, 138, 221, 10, 41, 13, 241, 60, 210, 216, 23, 62, 178, 73, | ||
111, | ||
]; | ||
const dsnp_keys = { | ||
dsnpUserId: dsnp_key_owner.toString(), | ||
keysHash: 100, | ||
keys: [ | ||
{ | ||
index: 0, | ||
content: new Uint8Array(published_keys_blob), | ||
}, | ||
], | ||
}; | ||
const deserialized_keys = graph_1.Graph.deserializeDsnpKeys(dsnp_keys); | ||
expect(deserialized_keys).toBeDefined(); | ||
}); | ||
test("generateKeyPair should return a key pair", async () => { | ||
const keyPair = graph_1.Graph.generateKeyPair(models_1.GraphKeyType.X25519); | ||
expect(keyPair).toBeDefined(); | ||
expect(keyPair.publicKey).toBeDefined(); | ||
expect(keyPair.secretKey).toBeDefined(); | ||
expect(keyPair.keyType).toEqual(models_1.GraphKeyType.X25519); | ||
}); | ||
}); | ||
test('generateKeyPair should return a key pair', async () => { | ||
const keyPair = await graph_1.Graph.generateKeyPair(models_1.GraphKeyType.X25519); | ||
expect(keyPair).toBeDefined(); | ||
expect(keyPair.publicKey).toBeDefined(); | ||
expect(keyPair.secretKey).toBeDefined(); | ||
expect(keyPair.keyType).toEqual(models_1.GraphKeyType.X25519); | ||
}); | ||
//# sourceMappingURL=graph.test.js.map |
@@ -37,3 +37,3 @@ "use strict"; | ||
const importBundle = { | ||
dsnpUserId: this.values.dsnpUserId || '', | ||
dsnpUserId: this.values.dsnpUserId || "", | ||
schemaId: this.values.schemaId || 0, | ||
@@ -40,0 +40,0 @@ keyPairs: this.values.keyPairs || [], |
@@ -6,5 +6,5 @@ "use strict"; | ||
const import_bundle_builder_1 = require("./import-bundle-builder"); | ||
describe('ImportBundleBuilder', () => { | ||
it('should build the import bundle correctly', () => { | ||
const dsnpUserId = '1000'; | ||
describe("ImportBundleBuilder", () => { | ||
it("should build the import bundle correctly", () => { | ||
const dsnpUserId = "1000"; | ||
const schemaId = 123; | ||
@@ -19,3 +19,3 @@ const keyPairs = [ | ||
const dsnpKeys = { | ||
dsnpUserId: '1000', | ||
dsnpUserId: "1000", | ||
keysHash: 456, | ||
@@ -34,3 +34,9 @@ keys: [{ index: 0, content: new Uint8Array([7, 8, 9]) }], | ||
.withSchemaId(schemaId) | ||
.withGraphKeyPairs([{ keyType: models_1.GraphKeyType.X25519, publicKey: new Uint8Array([1, 2, 3]), secretKey: new Uint8Array([4, 5, 6]) }]) | ||
.withGraphKeyPairs([ | ||
{ | ||
keyType: models_1.GraphKeyType.X25519, | ||
publicKey: new Uint8Array([1, 2, 3]), | ||
secretKey: new Uint8Array([4, 5, 6]), | ||
}, | ||
]) | ||
.withDsnpKeys(dsnpKeys) | ||
@@ -47,3 +53,3 @@ .withPageData(1, new Uint8Array([10, 11, 12]), 789); | ||
}); | ||
it('should build the import bundle correctly with withGraphKeyPair', () => { | ||
it("should build the import bundle correctly with withGraphKeyPair", () => { | ||
const dsnpUserId = "111"; | ||
@@ -55,3 +61,7 @@ const schemaId = 123; | ||
.withGraphKeyPair(models_1.GraphKeyType.X25519, new Uint8Array([1, 2, 3]), new Uint8Array([4, 5, 6])) | ||
.withDsnpKeys({ dsnpUserId: "111", keysHash: 456, keys: [{ index: 0, content: new Uint8Array([7, 8, 9]) }] }) | ||
.withDsnpKeys({ | ||
dsnpUserId: "111", | ||
keysHash: 456, | ||
keys: [{ index: 0, content: new Uint8Array([7, 8, 9]) }], | ||
}) | ||
.withPageData(1, new Uint8Array([10, 11, 12]), 789); | ||
@@ -61,5 +71,17 @@ (0, globals_1.expect)(importBundleBuilder.build()).toEqual({ | ||
schemaId, | ||
keyPairs: [{ keyType: models_1.GraphKeyType.X25519, publicKey: new Uint8Array([1, 2, 3]), secretKey: new Uint8Array([4, 5, 6]) }], | ||
dsnpKeys: { dsnpUserId: "111", keysHash: 456, keys: [{ index: 0, content: new Uint8Array([7, 8, 9]) }] }, | ||
pages: [{ pageId: 1, content: new Uint8Array([10, 11, 12]), contentHash: 789 }], | ||
keyPairs: [ | ||
{ | ||
keyType: models_1.GraphKeyType.X25519, | ||
publicKey: new Uint8Array([1, 2, 3]), | ||
secretKey: new Uint8Array([4, 5, 6]), | ||
}, | ||
], | ||
dsnpKeys: { | ||
dsnpUserId: "111", | ||
keysHash: 456, | ||
keys: [{ index: 0, content: new Uint8Array([7, 8, 9]) }], | ||
}, | ||
pages: [ | ||
{ pageId: 1, content: new Uint8Array([10, 11, 12]), contentHash: 789 }, | ||
], | ||
}); | ||
@@ -66,0 +88,0 @@ }); |
@@ -1,22 +0,23 @@ | ||
import { Action, Config, ConnectionType, DsnpGraphEdge, DsnpKeys, DsnpPublicKey, EnvironmentInterface, GraphKeyPair, GraphKeyType, ImportBundle, PrivacyType, Update } from "./models"; | ||
import { Action, ActionOptions, Config, ConnectionType, DsnpGraphEdge, DsnpKeys, DsnpPublicKey, EnvironmentInterface, GraphKeyPair, GraphKeyType, ImportBundle, PrivacyType, Update } from "./models"; | ||
export interface Native { | ||
printHelloGraph(): void; | ||
initializeGraphState(environment: EnvironmentInterface): number; | ||
getGraphConfig(environment: EnvironmentInterface): Promise<Config>; | ||
getSchemaIdFromConfig(environment: EnvironmentInterface, connectionType: ConnectionType, privacyType: PrivacyType): Promise<number>; | ||
getGraphStatesCount(): Promise<number>; | ||
getGraphUsersCount(handle: number): Promise<number>; | ||
containsUserGraph(handle: number, dsnpUserId: string): Promise<boolean>; | ||
removeUserGraph(handle: number, dsnpUserId: string): Promise<boolean>; | ||
importUserData(handle: number, payload: ImportBundle[]): Promise<boolean>; | ||
applyActions(handle: number, actions: Action[]): Promise<boolean>; | ||
exportUpdates(handle: number): Promise<Update[]>; | ||
getConnectionsForUserGraph(handle: number, dsnpUserId: string, schemaId: number, includePending: boolean): Promise<DsnpGraphEdge[]>; | ||
forceCalculateGraphs(handle: number, dsnpUserId: string): Promise<Update[]>; | ||
getConnectionsWithoutKeys(handle: number): Promise<string[]>; | ||
getOneSidedPrivateFriendshipConnections(handle: number, dsnpUserId: string): Promise<DsnpGraphEdge[]>; | ||
getPublicKeys(handle: number, dsnpUserId: string): Promise<DsnpPublicKey[]>; | ||
deserializeDsnpKeys(keys: DsnpKeys): Promise<DsnpPublicKey[]>; | ||
generateKeyPair(keyType: GraphKeyType): Promise<GraphKeyPair>; | ||
freeGraphState(handle: number): Promise<boolean>; | ||
getGraphConfig(environment: EnvironmentInterface): Config; | ||
getSchemaIdFromConfig(environment: EnvironmentInterface, connectionType: ConnectionType, privacyType: PrivacyType): number; | ||
getGraphStatesCount(): number; | ||
getGraphUsersCount(handle: number): number; | ||
containsUserGraph(handle: number, dsnpUserId: string): boolean; | ||
removeUserGraph(handle: number, dsnpUserId: string): boolean; | ||
importUserData(handle: number, payload: ImportBundle[]): boolean; | ||
applyActions(handle: number, actions: Action[], options?: ActionOptions): boolean; | ||
exportUpdates(handle: number): Update[]; | ||
exportUserGraphUpdates(handle: number, dsnpUserId: string): Update[]; | ||
getConnectionsForUserGraph(handle: number, dsnpUserId: string, schemaId: number, includePending: boolean): DsnpGraphEdge[]; | ||
forceCalculateGraphs(handle: number, dsnpUserId: string): Update[]; | ||
getConnectionsWithoutKeys(handle: number): string[]; | ||
getOneSidedPrivateFriendshipConnections(handle: number, dsnpUserId: string): DsnpGraphEdge[]; | ||
getPublicKeys(handle: number, dsnpUserId: string): DsnpPublicKey[]; | ||
deserializeDsnpKeys(keys: DsnpKeys): DsnpPublicKey[]; | ||
generateKeyPair(keyType: GraphKeyType): GraphKeyPair; | ||
freeGraphState(handle: number): boolean; | ||
} | ||
@@ -23,0 +24,0 @@ export declare const graphsdkModule: Native; |
@@ -6,26 +6,29 @@ "use strict"; | ||
const environment_1 = require("./models/environment"); | ||
function getTestConfig() { | ||
const config = {}; | ||
config.sdkMaxStaleFriendshipDays = 100; | ||
config.maxPageId = 100; | ||
config.dsnpVersions = [models_1.DsnpVersion.Version1_0]; | ||
config.maxGraphPageSizeBytes = 100; | ||
config.maxKeyPageSizeBytes = 100; | ||
const schemaConfig = {}; | ||
schemaConfig.dsnpVersion = models_1.DsnpVersion.Version1_0; | ||
schemaConfig.connectionType = models_1.ConnectionType.Follow; | ||
schemaConfig.privacyType = models_1.PrivacyType.Public; | ||
config.schemaMap = { 1: schemaConfig }; | ||
config.graphPublicKeySchemaId = 11; | ||
return config; | ||
} | ||
const config = { | ||
sdkMaxStaleFriendshipDays: 100, | ||
maxPageId: 100, | ||
dsnpVersions: [models_1.DsnpVersion.Version1_0], | ||
maxGraphPageSizeBytes: 100, | ||
maxKeyPageSizeBytes: 100, | ||
schemaMap: { | ||
1: { | ||
dsnpVersion: models_1.DsnpVersion.Version1_0, | ||
connectionType: models_1.ConnectionType.Follow, | ||
privacyType: models_1.PrivacyType.Public, | ||
}, | ||
}, | ||
graphPublicKeySchemaId: 11, | ||
}; | ||
test('printHelloGraph should print "Hello, Graph!"', async () => { | ||
// Mock the console.log function | ||
const consoleLogMock = jest.spyOn(console, 'log').mockImplementation(); | ||
const environment = { environmentType: environment_1.EnvironmentType.Dev, config: getTestConfig() }; | ||
const consoleLogMock = jest.spyOn(console, "log").mockImplementation(); | ||
const environment = { | ||
environmentType: environment_1.EnvironmentType.Dev, | ||
config, | ||
}; | ||
const graph = new graph_1.Graph(environment); | ||
graph.printHelloGraph(); | ||
expect(consoleLogMock).toHaveBeenCalledWith('Hello, Graph!'); | ||
await graph.freeGraphState(); | ||
expect(consoleLogMock).toHaveBeenCalledWith("Hello, Graph!"); | ||
graph.freeGraphState(); | ||
}); | ||
//# sourceMappingURL=index.test.js.map |
import { Connection } from "./connection"; | ||
import { DsnpKeys } from "./import_bundle"; | ||
export interface ActionOptions { | ||
ignoreExistingConnections?: boolean; | ||
ignoreMissingConnections?: boolean; | ||
} | ||
export interface ConnectAction { | ||
@@ -4,0 +8,0 @@ type: "Connect"; |
@@ -18,3 +18,3 @@ import { Config } from "./config"; | ||
type EnvironmentConfig = DevEnvironment; | ||
export { EnvironmentType, Environment, DevEnvironment, EnvironmentConfig, EnvironmentInterface }; | ||
export { EnvironmentType, Environment, DevEnvironment, EnvironmentConfig, EnvironmentInterface, }; | ||
//# sourceMappingURL=environment.d.ts.map |
@@ -26,3 +26,3 @@ "use strict"; | ||
__exportStar(require("./environment"), exports); | ||
//# sourceMappingURL=index.js.map | ||
// # sourceMappingURL=index.js.map | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "@dsnp/graph-sdk", | ||
"version": "0.0.9", | ||
"version": "0.0.10", | ||
"author": "Amplica Labs", | ||
@@ -33,2 +33,5 @@ "license": "Apache-2.0", | ||
"eslint": "^8.42.0", | ||
"eslint-config-airbnb-base": "^15.0.0", | ||
"eslint-config-prettier": "^8.8.0", | ||
"eslint-plugin-prettier": "^5.0.0", | ||
"jest": "^29.5.0", | ||
@@ -35,0 +38,0 @@ "ts-jest": "^29.1.0" |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
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
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
6405454
937
11