@authzed/authzed-js-node
Version:
authzed js client for nodejs
287 lines • 13.5 kB
JavaScript
/* eslint-disable @typescript-eslint/no-explicit-any */
"use strict";
import { promisify } from "util";
import { ExperimentalServiceClient } from "./authzedapi/authzed/api/v1/experimental_service.grpc-client.js";
import { PermissionsServiceClient } from "./authzedapi/authzed/api/v1/permission_service.grpc-client.js";
import { SchemaServiceClient } from "./authzedapi/authzed/api/v1/schema_service.grpc-client.js";
import { WatchServiceClient } from "./authzedapi/authzed/api/v1/watch_service.grpc-client.js";
import { WatchPermissionsServiceClient } from "./authzedapi/authzed/api/materialize/v0/watchpermissions.grpc-client.js";
import { WatchPermissionSetsServiceClient } from "./authzedapi/authzed/api/materialize/v0/watchpermissionsets.grpc-client.js";
import * as util from "./util.js";
import { ClientSecurity, PreconnectServices, deadlineInterceptor, promisifyStream, } from "./util.js";
import { Struct as ImportedPbStruct, NullValue as ImportedPbNullValue, } from "./authzedapi/google/protobuf/struct.js";
export { ImportedPbStruct as PbStruct, ImportedPbNullValue as PbNullValue };
const DEFAULT_DEADLINE_MS = 30 * 1000; // 30 seconds
/**
* A standard client (via @grpc/grpc-js) that will correctly
* proxy the namespaced methods to the correct service client.
*/
class ZedClient {
endpoint;
creds;
acl;
ns;
watch;
experimental;
watchPermissions;
watchPermissionSets;
options;
constructor(endpoint, creds, preconnect, options) {
this.endpoint = endpoint;
this.creds = creds;
this.options = {
...(options ?? {}),
interceptors: [
...(options?.interceptors ?? []),
// We put this interceptor last because it checks if the deadline is already
// set and, if so, does not overwrite it.
deadlineInterceptor(DEFAULT_DEADLINE_MS),
],
};
if (preconnect & PreconnectServices.PERMISSIONS_SERVICE) {
this.acl = new PermissionsServiceClient(this.endpoint, this.creds, options);
}
if (preconnect & PreconnectServices.SCHEMA_SERVICE) {
this.ns = new SchemaServiceClient(this.endpoint, this.creds, options);
}
if (preconnect & PreconnectServices.WATCH_SERVICE) {
this.watch = new WatchServiceClient(this.endpoint, this.creds, options);
}
if (preconnect & PreconnectServices.WATCH_PERMISSIONS_SERVICE) {
this.watchPermissions = new WatchPermissionsServiceClient(this.endpoint, this.creds, options);
}
if (preconnect & PreconnectServices.WATCH_PERMISSIONSETS_SERVICE) {
this.watchPermissionSets = new WatchPermissionSetsServiceClient(this.endpoint, this.creds, options);
}
if (preconnect & PreconnectServices.EXPERIMENTAL_SERVICE) {
this.experimental = new ExperimentalServiceClient(this.endpoint, this.creds, options);
}
}
static create(endpoint, creds, preconnect, options) {
return new Proxy({}, new ZedClient(endpoint, creds, preconnect, options));
}
close = () => {
[
this.acl,
this.ns,
this.watch,
this.experimental,
this.watchPermissions,
this.watchPermissionSets,
].forEach((client) => client?.close());
};
get(_target, name) {
if (name === "close") {
return this.close;
}
// If the name is a symbol, pass it to the underlying gRPC code.
// NOTE: it doesn't really matter to which client we give symbols, so just
// pick ACL by default since its the most likely be used.
if (typeof name === "symbol") {
if (this.acl === undefined) {
this.acl = new PermissionsServiceClient(this.endpoint, this.creds, this.options);
}
return this.acl[name];
}
// Otherwise, lazily instantiate the client based on the method requested.
if (name in PermissionsServiceClient.prototype) {
if (this.acl === undefined) {
this.acl = new PermissionsServiceClient(this.endpoint, this.creds, this.options);
}
return this.acl[name];
}
if (name in SchemaServiceClient.prototype) {
if (this.ns === undefined) {
this.ns = new SchemaServiceClient(this.endpoint, this.creds, this.options);
}
return this.ns[name];
}
if (name in WatchServiceClient.prototype) {
if (this.watch === undefined) {
this.watch = new WatchServiceClient(this.endpoint, this.creds, this.options);
}
return this.watch[name];
}
if (name in WatchPermissionsServiceClient.prototype) {
if (this.watchPermissions === undefined) {
this.watchPermissions = new WatchPermissionsServiceClient(this.endpoint, this.creds, this.options);
}
return this.watchPermissions[name];
}
if (name in WatchPermissionSetsServiceClient.prototype) {
if (this.watchPermissionSets === undefined) {
this.watchPermissionSets = new WatchPermissionSetsServiceClient(this.endpoint, this.creds, this.options);
}
return this.watchPermissionSets[name];
}
if (name in ExperimentalServiceClient.prototype) {
if (this.experimental === undefined) {
this.experimental = new ExperimentalServiceClient(this.endpoint, this.creds, this.options);
}
return this.experimental[name];
}
return undefined;
}
}
/**
* Proxies all methods from the {@link ZedDefaultClientInterface} to return promises
* in order to support async/await for {@link ClientUnaryCall} and {@link ClientReadableStream}
* responses. Methods that normally return an instance of stream, will instead return an
* array of objects collected while the stream was open.
*
* @param client The default grpc1 client
* @returns A promise-wrapped grpc1 client
*/
class ZedPromiseClient {
client;
promiseCache = {};
streamMethods = new Set([
"readRelationships",
"lookupResources",
"lookupSubjects",
"bulkExportRelationships",
"exportBulkRelationships",
"watchPermissions",
"watchPermissionSets",
]);
writableStreamMethods = new Set([
"bulkImportRelationships",
"importBulkRelationships",
]);
constructor(client) {
this.client = client;
}
static create(client) {
return new Proxy({}, new ZedPromiseClient(client));
}
get(_target, name) {
if (!(name in this.promiseCache)) {
const clientMethod = this.client[name];
if (clientMethod !== undefined) {
if (this.streamMethods.has(name)) {
this.promiseCache[name] = promisifyStream(clientMethod, this.client);
}
else if (this.writableStreamMethods.has(name)) {
this.promiseCache[name] = clientMethod.bind(this.client);
}
else if (typeof clientMethod === "function") {
this.promiseCache[name] = promisify(this.client[name]).bind(this.client);
}
else {
return clientMethod;
}
}
}
return this.promiseCache[name];
}
}
/**
* The {@link ZedCombinedClient} proxies both callback/promise-style methods to the underlying
* {@link ZedClient} and {@link ZedPromiseClient} instances. Direct method calls on the combined
* client will result in calling the underlying callback methods (the generated gRPC methods) while
* the same methods accessed at a sub-path `.promises.<method>` will result in the promise-wrapped
* methods.
*/
class ZedCombinedClient {
client;
promiseClient;
constructor(client, promiseClient) {
this.client = client;
this.promiseClient = promiseClient;
}
static create(endpoint, creds, preconnect, options) {
const client = ZedClient.create(endpoint, creds, preconnect, options);
const promiseClient = ZedPromiseClient.create(client);
return new Proxy({}, new ZedCombinedClient(client, promiseClient));
}
get(_target, name) {
if (name === "promises") {
return this.promiseClient;
}
return this.client[name];
}
}
/**
* NewClient creates a new client for calling Authzed APIs.
* @param token Secret token for authentication.
* @param endpoint Uri for communicating with Authzed.
* @param security Security level for the connection.
* @param preconnect The services to which the client will preconnect.
* All others will open a connection when first used.
* @returns Client for calling Authzed APIs.
*/
export function NewClient(token, endpoint = util.authzedEndpoint, security = ClientSecurity.SECURE, preconnect = PreconnectServices.PERMISSIONS_SERVICE, options = undefined) {
const creds = util.createClientCreds(endpoint, token, security);
return NewClientWithChannelCredentials(endpoint, creds, preconnect, options);
}
/**
* NewClientWithCustomCert creates a new client for calling Authzed APIs using a custom TLS certificate.
* @param token Secret token for authentication.
* @param endpoint Uri for communicating with Authzed.
* @param certificate Buffer read from certificate file.
* @param preconnect The services to which the client will preconnect.
* All others will open a connection when first used.
* @returns Client for calling Authzed APIs.
*/
export function NewClientWithCustomCert(token, endpoint = util.authzedEndpoint, certificate, preconnect = PreconnectServices.PERMISSIONS_SERVICE, options = undefined) {
const creds = util.createClientCredsWithCustomCert(token, certificate);
return NewClientWithChannelCredentials(endpoint, creds, preconnect, options);
}
/**
* NewClientWithChannelCredentials creates a new client for calling Authzed APIs using custom grpc ChannelCredentials.
*
The {@link ZedCombinedClient} proxies both callback/promise-style methods to the underlying
* {@link ZedClient} and {@link ZedPromiseClient} instances. Direct method calls on the combined
* client will result in calling the underlying callback methods (the generated gRPC methods) while
* the same methods accessed at a sub-path `.promises.<method>` will result in the promise-wrapped
* methods. For all methods that return a {@link ClientReadableStream}, the promise-wrapped method
* will return an array of the resulting responses after the stream has been closed.
*
* @param endpoint Uri for communicating with Authzed.
* @param creds ChannelCredentials used for grpc.
* @param preconnect The services to which the client will preconnect.
* All others will open a connection when first used.
* @returns Client for calling Authzed APIs.
*/
export function NewClientWithChannelCredentials(endpoint = util.authzedEndpoint, creds, preconnect = PreconnectServices.PERMISSIONS_SERVICE, options = undefined) {
return ZedCombinedClient.create(endpoint, creds, preconnect, options);
}
/**
* Creates a google.protobuf.Struct object suitable for use as
* optionalTransactionMetadata in WriteRelationshipsRequest.
*
* @param data A simple JavaScript object (e.g., { key: "value" }) to be converted into a Struct.
* @returns A google.protobuf.Struct object.
*/
export function createStructFromObject(data) {
try {
return ImportedPbStruct.fromJson(data);
}
catch (error) {
if (error instanceof Error &&
error.message.includes("Unable to parse message google.protobuf.Struct from JSON")) {
throw new Error("Input data for createStructFromObject must be a non-null object.");
}
throw error;
}
}
export * from "./authzedapi/authzed/api/v1/core.js";
export * from "./authzedapi/authzed/api/v1/experimental_service.js";
export * from "./authzedapi/authzed/api/v1/experimental_service.grpc-client.js";
export * from "./authzedapi/authzed/api/v1/permission_service.js";
export * from "./authzedapi/authzed/api/v1/permission_service.grpc-client.js";
export * from "./authzedapi/authzed/api/v1/schema_service.js";
export * from "./authzedapi/authzed/api/v1/schema_service.grpc-client.js";
export * from "./authzedapi/authzed/api/v1/watch_service.js";
export * from "./authzedapi/authzed/api/v1/watch_service.grpc-client.js";
export * from "./authzedapi/authzed/api/materialize/v0/watchpermissions.js";
export * from "./authzedapi/authzed/api/materialize/v0/watchpermissions.grpc-client.js";
// NOTE: these are explicitly enumerated because `Cursor` collides with a name in `core` and there isn't an easy way to say
// "import everything except this name" in TS imports.
export { WatchPermissionSetsRequest, WatchPermissionSetsResponse, Cursor as MaterializeCursor, LookupPermissionSetsRequest, LookupPermissionSetsResponse, PermissionSetChange, PermissionSetChange_SetOperation, SetReference, MemberReference, LookupPermissionSetsRequired, BreakingSchemaChange, } from "./authzedapi/authzed/api/materialize/v0/watchpermissionsets.js";
export * from "./authzedapi/authzed/api/materialize/v0/watchpermissionsets.grpc-client.js";
export { ClientSecurity } from "./util.js";
export default {
NewClient: NewClient,
};
//# sourceMappingURL=v1.js.map