mcpField
S
sasjs-adapter

sasjs-adapter

github.com/sasjs开发31.1k 次安装2 天前更新
代码仓库

关于 sasjs-adapter

为浏览器和 Node.js 提供调用 SAS 服务与作业的 TypeScript 库,通过统一 API 支持 SAS9、SASVIYA 和 SASJS。适合需要在 JavaScript 应用中提交 SAS 数据并读取结果的开发者。

主要功能

  1. 01统一调用三类 SAS 服务
  2. 02将输入表序列化为 CSV
  3. 03支持参数传输与文件上传
  4. 04管理认证与会话
  5. 05记录请求历史并可读取日志

适用场景

  1. 01从浏览器提交数据表并调用 SAS 作业
  2. 02在 Node.js 中连接 Viya 并提交作业
  3. 03调试请求并检查 SAS 日志

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/sasjs/skills --skill sasjs-adapter

安装后在 Claude Code 中输入/sasjs-adapter确认已加载。

详细介绍

@sasjs/adapter

@sasjs/adapter 是一个 TypeScript 库,可从浏览器或 Node 调用 SAS 服务/作业,并通过统一的 API 支持三种服务器类型:SAS9、SASVIYA、SASJS。

基本设置

import SASjs from '@sasjs/adapter'

const sasjs = new SASjs({
  serverUrl: 'https://sas.example.com',
  serverType: 'SASVIYA',      // SAS9 | SASVIYA | SASJS
  appLoc: '/Public/app/myapp', // root folder of deployed services
  contextName: 'SAS Job Execution compute context', // Viya only
  debug: false
})

request() - 输入(JS -> SAS)

签名
sasjs.request(
  sasJob: string,
  data: { [key: string]: any[] } | null,
  config?: { [key: string]: any },             // merged over SASjsConfig
  loginRequiredCallback?: () => any,
  authConfig?: AuthConfig,                      // Viya tokens for Node usage
  extraResponseAttributes?: ExtraResponseAttributes[]  // ['log'] | ['file'] | ['data']
)
  • sasJob:相对于 appLoc 解析的路径(不带前导斜杠),或绝对路径。它会成为 SAS _program 参数。
  • data:一个对象,其键会成为 SAS 中的 work 数据集。如果服务不需要输入,可以是 null。
  • config:仅对本次调用生效的配置,会覆盖构造函数配置。
data 对象 - 表,而非任意 JSON

data 中的每个键都必须对应一个普通对象数组。每个键会成为一个以该键命名的 SAS work 数据集;数组中的每个对象是一行;每个属性是一列。

const res = await sasjs.request('services/common/getdata', {
  customers: [
    { id: 1, name: 'Acme', active: true },
    { id: 2, name: 'Globex', active: false }
  ],
  config: [{ rootdir: '/tmp', retries: 3 }]  // even a single-row "config" table
})

在 SAS 端,这些数据会作为 work.customers 和 work.config 接收。

输入验证规则

发送前,适配器会验证 data(参见 validateInput)。如果违反规则,Promise 会以 ErrorResponse 拒绝:

  • data 必须为 null 或普通对象(不能是数组或原始值)。
  • 每个表的键必须以字母或下划线开头:/^[a-zA-Z_][a-zA-Z0-9_]*$/。不允许以数字开头。
  • 表名不得超过 32 个字符(SAS 名称长度限制)。
  • 每个键对应的值都必须是对象数组。不允许出现非对象行。
  • 任意行中的属性都不能为 undefined(必须是 null、字符串、数字或布尔值)。
表如何序列化为 CSV

每个表都会通过 convertToCSV 转换为 CSV。转换时会识别数据类型:

  • 字符串列:仅当包含逗号、制表符、换行符或引号时才加引号。内部的 " 会转义为 ""。
  • 数字列:不加引号。
  • 数字列中的 null / 空值:转换为 .(SAS 缺失值)。
  • 列类型推断:适配器会扫描每列的所有行。如果某列同时包含 null/number 值和特殊缺失值字符串(.a-.z、_),则该列的类型为 best.。否则,第一个非空值决定该列是 chars 还是 number。
  • 列格式标头:CSV 的第一行是以空格分隔的格式规范,例如 name:$char20. id:best.;SAS 端会使用它来指定输入格式。
  • 字节大小长度检查:字符串值按 UTF-8 字节数计量。如果任何值超过 32765 字节,请求会抛出 The max length of a string value in SASjs is 32765 characters.
  • 格式表:以 $ 为前缀的键(例如 $customers)会被视为 customers 表的格式定义,不会作为单独的数据集发送。其 formats 属性将列名映射到 SAS 格式。
两种传输模式

适配器会根据负载大小和服务器类型选择传输方式(参见 WebJobExecutor):

  1. 基于参数(Viya Web / SASjs 服务器的默认方式,适用于小型负载):每个表的 CSV 会作为名为 sasjs{N}data 的表单字段追加(N = 1、2、...)。sasjs_tables 字段会以空格分隔的形式列出表名。如果单个 CSV 超过 16000 个字符,则会拆分为多个块:sasjs{N}data0 存放块数,sasjs{N}data1..N 存放各块内容。
  2. 文件上传(始终用于 SAS 9;当 JSON.stringify(data) 超过 500000 个字符或包含 ; 时用于 Viya/SASjs):每个表都会作为 CSV 文件({tableName}.csv)追加到 multipart 表单数据中。

两种情况下,请求体都是 multipart/form-data;当 debug: true 时,会包含调试参数(_debug=131、_omittextlog=false、_omitSessionResults=false)。

request() - 输出(SAS -> JS)

响应结构取决于 extraResponseAttributes

默认情况(没有 extraResponseAttributes):解析后的值是解析得到的 webout 对象本身,也就是 SAS 服务写入 _webout 的任意 JSON:

// SAS service wrote: {"mydata":[{"COL1":"x","COL2":1}]}
const res = await sasjs.request('services/getdata', { in: [{ a: 1 }] })
// res === { mydata: [{ COL1: 'x', COL2: 1 }] }
// res.mydata[0].COL1  // note UPPERCASE column names

带有 extraResponseAttributes 时(例如 ['log']):结果会被包装:

const res = await sasjs.request('services/getdata', { in: [{ a: 1 }] }, {}, undefined, undefined, ['log'])
// res === { result: { mydata: [...] }, log: '<sas log string>' }

ExtraResponseAttributes 的取值为 'file' | 'data' | 'log'。当前版本仅完整实现了 log。

名称大小写
  • 响应中的表名为小写——这是由 SAS 端的 %webout/mp_jsonout 宏强制执行的,而非适配器。适配器会原样传递 webout JSON。
  • 列名为大写——SAS 数据集变量名会由 SAS 自身转换为大写,适配器不会更改其大小写。
SAS 服务必须生成的内容

服务必须将有效的 JSON 写入 _webout。通常通过 %webout(来自 @sasjs/core)实现,该宏会封装 mp_jsonout。JSON 结构是一个对象,其键为表名,每个键对应一个行对象数组:

%webout(OPEN)
%webout(OBJ, work.customers)   /* -> {"customers":[{...}]} */
%webout(CLOSE)
调试模式

当 config.debug 为 true 时:

  • SAS 9:原始响应是一个字符串,包含日志和 webout,两者由 >>weboutBEGIN<< 和 >>weboutEND<< 分隔。适配器会提取标记之间的 JSON。
  • Viya(web/JES):调试响应通过 parseSasViyaDebugResponse / parseSasViyaLogDebugResponse 解析,以分离日志和 webout JSON。
  • Viya(compute API):日志会从 compute 会话单独获取。

在所有情况下,开启调试并设置 extraResponseAttributes: ['log'] 后,都可以通过 res.log 获取 SAS 日志。

请求历史

每个已执行的请求都会追加到内存中的历史记录中(上限为 requestHistoryLimit,默认为 10):

sasjs.getSasRequests()
// SASjsRequest[]: { serviceLink, timestamp, sourceCode, generatedCode, logFile, SASWORK }

只有在 debug: true 时才会填充 sourceCode 和 generatedCode。历史记录采用环形缓冲区——超过上限时会丢弃最旧的条目。

身份验证

  • SAS 9:sasjs.logIn(username, password)(通过表单向存储过程服务进行身份验证)。会话 Cookie 会自动管理。
  • Viya:OAuth 客户端/密钥(客户端凭据授权)或授权码流程;令牌会自动刷新。Node 用法通过 CLI(sasjs add cred)配置。对于 Node,将 authConfig(客户端/密钥/访问/刷新令牌)传递给 request()。
  • SASJS server:针对 sasjs/server API 的基于令牌的身份验证。

主要类 / 模块

  • SASjs - 主入口:request()、logIn()/logOut()、uploadFile()、executeScript()、startComputeJob()、deployServicePack()
  • RequestClient - HTTP 层;保存请求历史(getRequests())、CSRF 令牌和身份验证标头
  • WebJobExecutor - SAS 9 STP、Viya web JES 和 SASjs server web(multipart form POST)
  • ComputeJobExecutor - Viya compute API(在指定上下文中直接提交代码)
  • JesJobExecutor - Viya JES API(通过 jobs API 提交作业,而非 web 应用)
  • SasjsJobExecutor - SASjs server web 执行
  • SessionManager - Viya compute 会话生命周期管理
  • SASViyaApiClient / SAS9ApiClient / SASjsApiClient - 各平台的底层客户端(很少需要直接使用)
  • file/ 工具 - 向 SAS 上传文件(处理二进制内容)

提示

  • 开发时设置 debug: true,以便在响应中显示 SAS 日志。
  • 始终处理 response.status / 错误响应——SAS 端错误(例如来自 %mp_abort 的错误)会出现在 JSON 中,不一定会作为 HTTP 错误返回。
  • 对于大型负载,优先使用 CSV 上传或流式文件,而非 JSON 输入表。
  • 确保 appLoc 与用于部署的 sasjsconfig.json 中的 appLoc 一致。
  • SAS 返回的列名为大写。如果前端需要小写,应在 JS 中进行映射,而不是尝试强制更改 SAS 的大小写。
  • 数值输入列中的 null 会变为 SAS 缺失值(.);字符列中的空字符串会保留为空字符串。不要使用 undefined——验证会拒绝它。

在不使用打包器的情况下使用适配器(零构建 / 严格 CSP 前端)

包根目录中的 index.js 是一个 UMD 包,会公开全局对象 SASjs。用法(取自最小种子应用):

  1. 在 package.json 中添加 "prepare": "cp node_modules/@sasjs/adapter/index.js src/sasjs.js"(在 npm i 时运行)。
  2. 在应用脚本之前添加 <script src="sasjs.js"></script>。
  3. 通过隐藏的自定义元素进行配置:<sasjs serverType="SASJS" appLoc="/Public/app/myapp" debug="false"></sasjs>,并使用 document.querySelector('sasjs') 读取属性。如果应用由 SAS 本身提供,则省略 serverUrl——同源请求可直接正常工作(符合 CSP default-src 'self')。

限制

此技能是 @sasjs/adapter 库的静态参考资料——提供有关 API、请求 / 响应格式、身份验证和 CSV 序列化的指南。它不会执行代码、运行 shell 命令、访问文件系统、连接数据库或发起网络请求。所有代码示例仅供说明;用户必须将其集成到自己的应用中。有关身份验证令牌的说明描述的是适配器库在运行时管理的内容——此技能本身不会读取、写入或访问这些值。

评论

支持 Markdown