Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions client/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,18 @@ import { InnerClient } from "./core.js";
import { SecretsApi, Secrets } from "./secrets.js";
import { ItemsApi, Items } from "./items.js";
import { VaultsApi, Vaults } from "./vaults.js";
import { GroupsApi, Groups } from "./groups.js";

export class Client {
public secrets: SecretsApi;
public items: ItemsApi;
public vaults: VaultsApi;
public groups: GroupsApi;

public constructor(innerClient: InnerClient) {
this.secrets = new Secrets(innerClient);
this.items = new Items(innerClient);
this.vaults = new Vaults(innerClient);
this.groups = new Groups(innerClient);
}
}
8 changes: 6 additions & 2 deletions client/src/client_builder.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Core, InnerClient } from "./core.js";
import { Core, InnerClient, SharedCore } from "./core.js";
import { ClientConfiguration, clientAuthConfig } from "./configuration.js";
import { Client } from "./client.js";
import { SharedLibCore } from "./shared_lib_core.js";

const finalizationRegistry = new FinalizationRegistry(
(heldClient: InnerClient) => {
Expand All @@ -14,9 +15,12 @@ const finalizationRegistry = new FinalizationRegistry(
*/
export const createClientWithCore = async (
config: ClientConfiguration,
core: Core,
core: SharedCore,
): Promise<Client> => {
const authConfig = clientAuthConfig(config);
if (authConfig.accountName) {
core.setInner(new SharedLibCore(authConfig.accountName));
}
const clientId = await core.initClient(authConfig);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

non blocker, just curious - why is the client ID needed here, since the authorization is going to be scoped on the process level and not the client level?

const inner: InnerClient = {
id: parseInt(clientId, 10),
Expand Down
24 changes: 22 additions & 2 deletions client/src/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,18 @@ export interface ClientConfiguration {
}

// Sets the authentication method. Use a token as a `string` to authenticate with a service account token.
type Auth = string;
type Auth = string | DesktopAuth;

/**
* Setting that specifies that a client should use the desktop app to authenticate.
*/
export class DesktopAuth {
public accountName: string;

public constructor(accountName: string) {
this.accountName = accountName;
}
}
/**
* Creates a default client configuration.
* @returns The client configuration to instantiate the client with.
Expand All @@ -25,8 +35,18 @@ export const clientAuthConfig = (
): ClientAuthConfig => {
// TODO: Add logic for computing the correct sanitized version value for each platform
const defaultOsVersion = "0.0.0";

let serviceAccountToken: string | undefined;
let accountName: string | undefined;

if (typeof userConfig.auth === "string") {
serviceAccountToken = userConfig.auth;
} else if (userConfig.auth instanceof DesktopAuth) {
accountName = userConfig.auth.accountName;
}
return {
serviceAccountToken: userConfig.auth ?? "",
serviceAccountToken: serviceAccountToken ?? "",
accountName,
programmingLanguage: LANGUAGE,
sdkVersion: VERSION,
integrationName: userConfig.integrationName,
Expand Down
60 changes: 47 additions & 13 deletions client/src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,21 @@ export interface Core {
/**
* Allocates a new authenticated client and returns its id.
*/
initClient(config: ClientAuthConfig): Promise<string>;
initClient(config: string): Promise<string>;
/**
* Calls async business logic from a given client and returns the result.
*/
invoke(config: InvokeConfig): Promise<string>;
/**
* Calls sync business logic from a given client and returns the result.
*/
invoke_sync(config: InvokeConfig): string;
invoke(config: string): Promise<string>;
/**
* Deallocates memory held by the given client in the SDK core when it goes out of scope.
*/
releaseClient(clientId: number): void;
releaseClient(clientId: string): void;
}

/**
* Wraps configuration information needed to allocate and authenticate a client instance and sends it to the SDK core.
*/
export interface ClientAuthConfig {
serviceAccountToken: string;
programmingLanguage: string;
sdkVersion: string;
integrationName: string;
Expand All @@ -49,6 +44,9 @@ export interface ClientAuthConfig {
os: string;
osVersion: string;
architecture: string;

serviceAccountToken?: string; // only used when service account token auth is selected
accountName?: string; // only used when desktop auth is selected
}

/**
Expand Down Expand Up @@ -83,14 +81,50 @@ export interface Parameters {
parameters: { [key: string]: unknown };
}

export class WasmCore implements Core {
public async initClient(config: string): Promise<string> {
try {
return await init_client(config);
} catch (e) {
throwError(e as string);
}
}

public async invoke(config: string): Promise<string> {
try {
return await invoke(config);
} catch (e) {
throwError(e as string);
}
}

public releaseClient(clientId: string): void {
try {
release_client(clientId);
} catch (e) {
console.warn("failed to release client:", e);
}
}
}

/**
* An implementation of the `Core` interface that shares resources across all clients.
*/
export class SharedCore implements Core {
export class SharedCore {
private inner: Core;

public constructor() {
this.inner = new WasmCore();
}

public setInner(core: Core) {
this.inner = core;
}

public async initClient(config: ClientAuthConfig): Promise<string> {
const serializedConfig = JSON.stringify(config);
try {
return await init_client(serializedConfig);
return await this.inner.initClient(serializedConfig);
} catch (e) {
throwError(e as string);
}
Expand All @@ -106,7 +140,7 @@ export class SharedCore implements Core {
);
}
try {
return await invoke(serializedConfig);
return await this.inner.invoke(serializedConfig);
} catch (e) {
throwError(e as string);
}
Expand All @@ -130,7 +164,7 @@ export class SharedCore implements Core {

public releaseClient(clientId: number): void {
const serializedId = JSON.stringify(clientId);
release_client(serializedId);
this.inner.releaseClient(serializedId);
}
}

Expand All @@ -139,5 +173,5 @@ export class SharedCore implements Core {
*/
export interface InnerClient {
id: number;
core: Core;
core: SharedCore;
}
41 changes: 41 additions & 0 deletions client/src/groups.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Code generated by op-codegen - DO NOT EDIT MANUALLY

import { InvokeConfig, InnerClient, SharedCore } from "./core.js";
import { Group, GroupGetParams, ReviverFunc } from "./types.js";

/**
* The Groups API holds all the operations the SDK client can perform on 1Password groups.
*/
export interface GroupsApi {
get(groupId: string, groupParams: GroupGetParams): Promise<Group>;
}

export class Groups implements GroupsApi {
#inner: InnerClient;

public constructor(inner: InnerClient) {
this.#inner = inner;
}

public async get(
groupId: string,
groupParams: GroupGetParams,
): Promise<Group> {
const invocationConfig: InvokeConfig = {
invocation: {
clientId: this.#inner.id,
parameters: {
name: "GroupsGet",
parameters: {
group_id: groupId,
group_params: groupParams,
},
},
},
};
return JSON.parse(
await this.#inner.core.invoke(invocationConfig),
ReviverFunc,
) as Group;
}
}
99 changes: 99 additions & 0 deletions client/src/items.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import {
ItemCreateParams,
ItemListFilter,
ItemOverview,
ItemsDeleteAllResponse,
ItemsGetAllResponse,
ItemsUpdateAllResponse,
ReviverFunc,
} from "./types.js";
import { ItemsSharesApi, ItemsShares } from "./items_shares.js";
Expand All @@ -22,11 +25,24 @@ export interface ItemsApi {
*/
create(params: ItemCreateParams): Promise<Item>;

/**
* Create items in batch, within a single vault.
*/
createAll(
vaultId: string,
params: ItemCreateParams[],
): Promise<ItemsUpdateAllResponse>;

/**
* Get an item by vault and item ID
*/
get(vaultId: string, itemId: string): Promise<Item>;

/**
* Get items by vault and their item IDs.
*/
getAll(vaultId: string, itemIds: string[]): Promise<ItemsGetAllResponse>;

/**
* Update an existing item.
*/
Expand All @@ -37,6 +53,14 @@ export interface ItemsApi {
*/
delete(vaultId: string, itemId: string);

/**
* Delete items in batch, within a single vault.
*/
deleteAll(
vaultId: string,
itemIds: string[],
): Promise<ItemsDeleteAllResponse>;

/**
* Archive an item.
*/
Expand Down Expand Up @@ -80,6 +104,31 @@ export class Items implements ItemsApi {
) as Item;
}

/**
* Create items in batch, within a single vault.
*/
public async createAll(
vaultId: string,
params: ItemCreateParams[],
): Promise<ItemsUpdateAllResponse> {
const invocationConfig: InvokeConfig = {
invocation: {
clientId: this.#inner.id,
parameters: {
name: "ItemsCreateAll",
parameters: {
vault_id: vaultId,
params,
},
},
},
};
return JSON.parse(
await this.#inner.core.invoke(invocationConfig),
ReviverFunc,
) as ItemsUpdateAllResponse;
}

/**
* Get an item by vault and item ID
*/
Expand All @@ -102,6 +151,31 @@ export class Items implements ItemsApi {
) as Item;
}

/**
* Get items by vault and their item IDs.
*/
public async getAll(
vaultId: string,
itemIds: string[],
): Promise<ItemsGetAllResponse> {
const invocationConfig: InvokeConfig = {
invocation: {
clientId: this.#inner.id,
parameters: {
name: "ItemsGetAll",
parameters: {
vault_id: vaultId,
item_ids: itemIds,
},
},
},
};
return JSON.parse(
await this.#inner.core.invoke(invocationConfig),
ReviverFunc,
) as ItemsGetAllResponse;
}

/**
* Update an existing item.
*/
Expand Down Expand Up @@ -142,6 +216,31 @@ export class Items implements ItemsApi {
await this.#inner.core.invoke(invocationConfig);
}

/**
* Delete items in batch, within a single vault.
*/
public async deleteAll(
vaultId: string,
itemIds: string[],
): Promise<ItemsDeleteAllResponse> {
const invocationConfig: InvokeConfig = {
invocation: {
clientId: this.#inner.id,
parameters: {
name: "ItemsDeleteAll",
parameters: {
vault_id: vaultId,
item_ids: itemIds,
},
},
},
};
return JSON.parse(
await this.#inner.core.invoke(invocationConfig),
ReviverFunc,
) as ItemsDeleteAllResponse;
}

/**
* Archive an item.
*/
Expand Down
1 change: 1 addition & 0 deletions client/src/sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export { Secrets } from "./secrets.js";
export * from "./client.js";
export * from "./errors.js";
export * from "./types.js";
export { DesktopAuth } from "./configuration.js";

/**
* Creates a default 1Password SDK client.
Expand Down
Loading