UNPKG

@authzed/authzed-js-node

Version:
287 lines 13.5 kB
/* 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