@larksuiteoapi/api
Version:
larksuite open api sdk
311 lines • 13 kB
JavaScript
;
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