UNPKG

@larksuiteoapi/api

Version:
311 lines 13 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.handle = exports.Default = exports.Handlers = exports.applyAppTicket = exports.unmarshalResponseFunc = void 0; const util = __importStar(require("util")); const request = __importStar(require("../request/request")); const formdata = __importStar(require("../request/formData")); const response = __importStar(require("../response/response")); const errors_1 = require("../errors/errors"); const node_fetch_1 = __importDefault(require("node-fetch")); const form_data_1 = __importDefault(require("form-data")); const error_1 = require("../response/error"); const token_1 = require("../token/token"); const accessToken_1 = require("./accessToken"); const constants_1 = require("../constants/constants"); const core_1 = require("@larksuiteoapi/core"); const fs = __importStar(require("fs")); const tempy_1 = __importDefault(require("tempy")); const stream = __importStar(require("stream")); const path_1 = __importDefault(require("path")); const defaultMaxRetryCount = 1; let defaultHTTPRequestHeader = new Map(); defaultHTTPRequestHeader.set("User-Agent", util.format("oapi-sdk-nodejs/%s", core_1.SdkVersion)); const initFunc = (ctx, req) => __awaiter(void 0, void 0, void 0, function* () { let conf = core_1.getConfigByCtx(ctx); req.init(conf.getDomain()); }); const validateFunc = (ctx, req) => __awaiter(void 0, void 0, void 0, function* () { if (req.accessTokenType == request.AccessTokenType.None) { return; } if (!req.accessibleTokenTypeSet.has(req.accessTokenType)) { errors_1.throwAccessTokenTypeIsInValidErr(); } if (core_1.getConfigByCtx(ctx).getAppSettings().appType === core_1.AppType.ISV) { if (req.accessTokenType === request.AccessTokenType.Tenant && !req.tenantKey) { errors_1.throwTenantKeyIsEmptyErr(); } if (req.accessTokenType === request.AccessTokenType.User && !req.userAccessToken) { errors_1.throwUserAccessTokenKeyIsEmptyErr(); } } }); const reqBodyFromFormData = (ctx, req) => { const form = new form_data_1.default(); let fd = req.input; Array.from(fd.getParams().entries()).forEach(([key, value]) => { form.append(key, value); }); let hasStream = false; for (let file of fd.getFiles()) { let opt = { filename: file.getName() }; if (file.getType()) { opt["contentType"] = file.getType(); } if (file.isStream()) { hasStream = true; } form.append(file.getFieldName(), file.getContent(), opt); } Object.entries(form.getHeaders()).forEach(([key, value]) => { req.httpRequestOpts.headers[key] = value; }); if (hasStream) { let filePath = tempy_1.default.directory({ prefix: "larksuiteoapi-", }); filePath = path_1.default.join(filePath, "formdata"); form.pipe(fs.createWriteStream(filePath)); req.httpRequestOpts.bodySource = { isStream: true, filePath: filePath, }; core_1.getConfigByCtx(ctx).getLogger().debug(util.format("[build]request:%s, formdata:%s", req, filePath)); } else { req.httpRequestOpts.body = form.getBuffer(); core_1.getConfigByCtx(ctx).getLogger().debug(util.format("[build]request:%s, formdata:", req), req.httpRequestOpts.body); } }; const reqBodyFromInput = (ctx, req) => { req.httpRequestOpts.headers[core_1.ContentType] = core_1.DefaultContentType; let input; if (typeof req.input == "string") { input = req.input; } else { input = JSON.stringify(req.input); } req.httpRequestOpts.body = input; core_1.getConfigByCtx(ctx).getLogger().debug(util.format("[build]request:%s, body:", req), req.httpRequestOpts.body); }; const buildFunc = (ctx, req) => __awaiter(void 0, void 0, void 0, function* () { if (!req.retryable) { let conf = core_1.getConfigByCtx(ctx); let opts = { method: req.httpMethod, timeout: req.timeout, headers: {}, }; Array.from(defaultHTTPRequestHeader).forEach(([key, value]) => { opts.headers[key.toLowerCase()] = value; }); req.httpRequestOpts = opts; if (req.input) { if (req.input instanceof formdata.FormData) { reqBodyFromFormData(ctx, req); } else { reqBodyFromInput(ctx, req); } } else { conf.getLogger().debug(util.format("[build]request:%s, not body", req)); } } }); const signFunc = (ctx, req) => __awaiter(void 0, void 0, void 0, function* () { switch (req.accessTokenType) { case request.AccessTokenType.App: yield accessToken_1.setAppAccessToken(ctx, req.httpRequestOpts.headers); break; case request.AccessTokenType.Tenant: yield accessToken_1.setTenantAccessToken(ctx, req.httpRequestOpts.headers); break; case request.AccessTokenType.User: yield accessToken_1.setUserAccessToken(ctx, req.httpRequestOpts.headers); break; } if (req.needHelpDeskAuth) { let helpDeskAuthorization = core_1.getConfigByCtx(ctx).getHelpDeskAuthorization(); if (!helpDeskAuthorization) { errors_1.throwHelpDeskAuthorizationIsEmptyErr(); } req.httpRequestOpts.headers["X-Lark-Helpdesk-Authorization"] = helpDeskAuthorization; } }); const validateResponseFunc = (_, req) => __awaiter(void 0, void 0, void 0, function* () { let resp = req.httpResponse; let contentType = resp.headers.get(core_1.ContentType.toLowerCase()); if (req.isResponseStream) { if (resp.ok) { req.isResponseStreamReal = true; return; } if (contentType && contentType.indexOf(core_1.ContentTypeJson) > -1) { req.isResponseStreamReal = false; return; } let content = yield resp.buffer(); throw error_1.newErrorOfInvalidResp(util.format("response is stream, but status code %d is not 200, content-type: %s, body: %s", resp.status, contentType, content)); } if (!contentType || contentType.indexOf(core_1.ContentTypeJson) === -1) { let content = yield resp.buffer(); throw error_1.newErrorOfInvalidResp(util.format("status code: %d, content-type %s is not %s, body: %s", resp.status, contentType, core_1.ContentTypeJson, content)); } }); exports.unmarshalResponseFunc = (ctx, req) => __awaiter(void 0, void 0, void 0, function* () { let resp = req.httpResponse; if (req.isResponseStreamReal) { if (req.output && req.output instanceof stream.Writable) { resp.body.pipe(req.output); req.response.data = req.output; return; } let body = yield resp.buffer(); req.output = body; req.response.data = req.output; return; } let json = yield resp.json(); core_1.getConfigByCtx(ctx).getLogger().debug(util.format("[unmarshalResponse] request:%s, response:body:", req), JSON.stringify(json)); req.retryable = retryable(json.code); Object.entries(json).forEach(([k, v]) => { req.response[k] = v; }); if (req.isNotDataField) { req.response.data = json; } }); const retryable = (code) => { let b = false; switch (code) { case error_1.ErrCode.AccessTokenInvalid: case error_1.ErrCode.AppAccessTokenInvalid: case error_1.ErrCode.TenantAccessTokenInvalid: b = true; break; } return b; }; // apply app ticket exports.applyAppTicket = (ctx) => __awaiter(void 0, void 0, void 0, function* () { let conf = core_1.getConfigByCtx(ctx); let req = request.newRequestByAuth(constants_1.URL.ApplyAppTicketPath, "POST", new token_1.ApplyAppTicketReq(conf.getAppSettings().appID, conf.getAppSettings().appSecret), {}); yield exports.handle(ctx, req); }); const deleteTmpFile = (ctx, req) => __awaiter(void 0, void 0, void 0, function* () { let conf = core_1.getConfigByCtx(ctx); let bodySource = req.httpRequestOpts.bodySource; if (bodySource && bodySource.isStream) { try { fs.unlinkSync(bodySource.filePath); } catch (err) { conf.getLogger().info(util.format("[complement] request:%s, delete tmp file(%s) err: ", req.toString()), bodySource.filePath, err); } } }); const complement = (ctx, req, err) => __awaiter(void 0, void 0, void 0, function* () { yield deleteTmpFile(ctx, req); if (err) { if (err instanceof errors_1.AppTicketIsEmptyErr) { yield exports.applyAppTicket(ctx); } throw err; } if (req.response && req.response.code == error_1.ErrCode.AppTicketInvalid) { yield exports.applyAppTicket(ctx); return; } }); class Handlers { constructor(init, validate, build, sign, validateResponse, unmarshalResponse) { this._send = (ctx, req) => __awaiter(this, void 0, void 0, function* () { yield this.build(ctx, req); yield this.sign(ctx, req); let bodySource = req.httpRequestOpts.bodySource; if (bodySource && bodySource.isStream) { req.httpRequestOpts.body = fs.createReadStream(bodySource.filePath); } req.httpResponse = yield node_fetch_1.default(req.url(), req.httpRequestOpts); let header = {}; req.httpResponse.headers.forEach((value, name) => { header[name.toLowerCase()] = value; }); ctx.set(core_1.HTTPHeaderKey, header); ctx.set(core_1.HTTPKeyStatusCode, req.httpResponse.status); req.response = new response.Response(ctx); yield this.validateResponse(ctx, req); yield this.unmarshalResponse(ctx, req); }); this.send = (ctx, req) => __awaiter(this, void 0, void 0, function* () { let i = 0; let conf = core_1.getConfigByCtx(ctx); do { i++; if (req.retryable) { conf.getLogger().debug(util.format("[retry] request:%s, response: ", req.toString()), req.response.toString()); } yield this._send(ctx, req); } while (req.retryable && i <= defaultMaxRetryCount); }); this.init = init; this.validate = validate; this.build = build; this.sign = sign; this.validateResponse = validateResponse; this.unmarshalResponse = unmarshalResponse; } } exports.Handlers = Handlers; exports.Default = new Handlers(initFunc, validateFunc, buildFunc, signFunc, validateResponseFunc, exports.unmarshalResponseFunc); exports.handle = (ctx, req) => __awaiter(void 0, void 0, void 0, function* () { let err; try { yield exports.Default.init(ctx, req); yield exports.Default.validate(ctx, req); yield exports.Default.send(ctx, req); } catch (e) { err = e; } finally { yield complement(ctx, req, err); } return req.response; }); //# sourceMappingURL=handlers.js.map