sasjs-adapter
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinese@sasjs/adapter
@sasjs/adapter
@sasjs/adapterSAS9SASVIYASASJS@sasjs/adapterSAS9SASVIYASASJSBasic setup
基本设置
ts
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
})ts
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() - inputs (JS -> SAS)
request() - 输入(JS -> SAS)
Signature
函数签名
ts
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']
)- : relative path (no leading slash) resolved against
sasJob, or an absolute path. Becomes the SASappLocparameter._program - : an object whose keys become work datasets in SAS. Can be
dataif the service takes no input.null - : overrides merged on top of the constructor config for this call only.
config
ts
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进行解析;也可以是绝对路径。它会成为 SAS 的appLoc参数。_program - :一个对象,其键会成为 SAS 中的 work 数据集。如果服务不需要输入,可以为
data。null - :仅在本次调用中覆盖并合并到构造函数配置之上的覆盖项。
config
The data
object - tables, not arbitrary JSON
datadata
对象——是表,而不是任意 JSON
dataEvery key in must be an array of plain objects. Each key becomes a SAS work dataset named after the key; each object in the array is a row; each property is a column.
datats
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
})On the SAS side these arrive as and .
work.customerswork.configdatats
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.customerswork.configInput validation rules
输入验证规则
Before sending, the adapter validates (see ). Violations reject the promise with an :
datavalidateInputErrorResponse- must be
dataor a plain object (not an array, not a primitive).null - Every table key must start with a letter or underscore: . Numbers at the start are rejected.
/^[a-zA-Z_][a-zA-Z0-9_]*$/ - Table names cannot exceed 32 characters (SAS name limit).
- Every value under a key must be an array of objects. Non-object rows are rejected.
- No property in any row may be (it must be
undefined, a string, a number, or a boolean).null
发送前,adapter 会验证 (参见 )。违反规则时,Promise 将以 拒绝:
datavalidateInputErrorResponse- 必须是
data或普通对象(不能是数组或基本类型)。null - 每个表键都必须以字母或下划线开头:。以数字开头的名称会被拒绝。
/^[a-zA-Z_][a-zA-Z0-9_]*$/ - 表名不能超过 32 个字符(SAS 名称长度限制)。
- 每个键对应的值都必须是对象数组。包含非对象行的数据会被拒绝。
- 任意行中的属性都不能为 (必须是
undefined、字符串、数字或布尔值)。null
How tables are serialized to CSV
表如何序列化为 CSV
Each table is converted to CSV via . The conversion is type-aware:
convertToCSV- String columns: quoted only if they contain commas, tabs, newlines, or quotes. Internal is escaped as
"."" - Numeric columns: emitted unquoted.
- Null / empty in a numeric column: becomes (SAS missing).
. - Column type inference: the adapter scans all rows per column. If a column has both /
nullvalues and special-missing strings (number-.a,.z), the column is typed as_. Otherwise the first non-empty value determinesbest.vschars.number - Column format header: the first CSV line is a space-delimited format spec, e.g. - the SAS side uses this to assign informats.
name:$char20. id:best. - Byte-size length check: string values are measured in UTF-8 bytes. If any value exceeds 32765 bytes, the request throws
The max length of a string value in SASjs is 32765 characters. - Formats tables: a key prefixed with (e.g.
$) is treated as a formats definition for the$customerstable and is not sent as a separate dataset. Itscustomersproperty maps column names to SAS formats.formats
每张表都会通过 转换为 CSV。该转换能够识别类型:
convertToCSV- 字符串列:仅当字符串包含逗号、制表符、换行符或引号时才添加引号。内部的 会转义为
"。"" - 数值列:不加引号直接输出。
- 数值列中的 null/空值:转换为 (SAS 缺失值)。
. - 列类型推断:adapter 会扫描每列的所有行。如果某列同时包含 /数字值和特殊缺失值字符串(
null-.a、.z),则该列的类型为_。否则,由第一个非空值决定列类型是best.还是chars。number - 列格式标题:CSV 的第一行是使用空格分隔的格式规范,例如 。SAS 端会使用它来指定 informat。
name:$char20. id:best. - 字节大小长度检查:字符串值按 UTF-8 字节计算长度。如果任何值超过 32765 字节,请求将抛出
The max length of a string value in SASjs is 32765 characters. - Formats 表:以 为前缀的键(例如
$)会被视为$customers表的 formats 定义,而不会作为单独的数据集发送。其customers属性用于将列名映射到 SAS format。formats
Two transport modes
两种传输模式
The adapter picks the transport based on payload size and server type (see ):
WebJobExecutor- Param-based (default for Viya web / SASjs server, small payloads): each table's CSV is appended as a form field named (N = 1, 2, ...). A
sasjs{N}datafield lists the table names space-separated. If a single CSV exceeds 16000 chars it is split into chunks:sasjs_tablesholds the chunk count,sasjs{N}data0hold the pieces.sasjs{N}data1..N - File-upload (SAS 9 always; Viya/SASjs when exceeds 500000 chars or contains a
JSON.stringify(data)): each table is appended as a CSV file (;) in multipart form data.{tableName}.csv
In both cases the body is with debug params (, , ) when .
multipart/form-data_debug=131_omittextlog=false_omitSessionResults=falsedebug: trueadapter 会根据负载大小和服务器类型选择传输方式(参见 ):
WebJobExecutor- 基于参数(Viya Web/SASJS 服务器处理小型负载时的默认方式):每张表的 CSV 会作为名为 的表单字段附加,其中 N = 1、2、……。
sasjs{N}data字段会列出以空格分隔的表名。如果单个 CSV 超过 16000 个字符,则会对其进行分块:sasjs_tables保存分块数量,sasjs{N}data0保存各个分块。sasjs{N}data1..N - 文件上传(SAS 9 始终使用此方式;当 超过 500000 个字符或包含
JSON.stringify(data)时,Viya/SASJS 也使用此方式):每张表都会作为 CSV 文件(;)附加到 multipart form data 中。{tableName}.csv
在这两种情况下,请求体都是 ;当 时,还会包含调试参数(、、)。
multipart/form-datadebug: true_debug=131_omittextlog=false_omitSessionResults=falserequest() - outputs (SAS -> JS)
request() - 输出(SAS -> JS)
Response shape depends on extraResponseAttributes
extraResponseAttributes响应结构取决于 extraResponseAttributes
extraResponseAttributesDefault (no ): the resolved value is the parsed webout object directly - whatever JSON the SAS service wrote to :
extraResponseAttributes_weboutts
// 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 namesWith (e.g. ): the result is wrapped:
extraResponseAttributes['log']ts
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默认情况(未设置 ):解析后的值就是 webout 对象本身,即 SAS 服务写入 的 JSON:
extraResponseAttributes_weboutts
// 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']ts
const res = await sasjs.request('services/getdata', { in: [{ a: 1 }] }, {}, undefined, undefined, ['log'])
// res === { result: { mydata: [...] }, log: '<sas log string>' }ExtraResponseAttributes'file' | 'data' | 'log'logName casing
名称大小写
- Table names in the response are lowercase - this is enforced by the /
%weboutmacro on the SAS side, not the adapter. The adapter passes the webout JSON through as-is.mp_jsonout - Column names are UPPERCASE - SAS dataset variable names are uppercased by SAS itself, and the adapter does not re-case them.
- 响应中的 表名为 小写。这是 SAS 端的 /
%webout宏强制执行的,并非由 adapter 处理。adapter 会原样传递 webout JSON。mp_jsonout - 列名为 大写。SAS 数据集变量名本身会被 SAS 转换为大写,adapter 不会再次转换大小写。
What the SAS service must produce
SAS 服务必须生成的内容
The service must write valid JSON to . Conventionally via (from @sasjs/core), which wraps . The JSON shape is an object whose keys are table names, each mapping to an array of row objects:
_webout%weboutmp_jsonoutsas
%webout(OPEN)
%webout(OBJ, work.customers) /* -> {"customers":[{...}]} */
%webout(CLOSE)服务必须向 写入有效的 JSON。通常可使用 (来自 ),它会包装 。JSON 的结构应为:对象中的键是表名,每个表名对应一个行对象数组:
_webout%webout@sasjs/coremp_jsonoutsas
%webout(OPEN)
%webout(OBJ, work.customers) /* -> {"customers":[{"..."}]} */
%webout(CLOSE)Debug mode
调试模式
When is :
config.debugtrue- SAS 9: the raw response is a string containing the log plus the webout, delimited by and
>>weboutBEGIN<<. The adapter extracts the JSON between the markers.>>weboutEND<< - Viya (web/JES): the debug response is parsed via /
parseSasViyaDebugResponse, which split out the log and the webout JSON.parseSasViyaLogDebugResponse - Viya (compute API): the log is fetched separately from the compute session.
In all cases, with debug on and , the SAS log is available in .
extraResponseAttributes: ['log']res.log当 为 时:
config.debugtrue- SAS 9:原始响应是一个字符串,其中包含日志和 webout,并以 和
>>weboutBEGIN<<分隔。adapter 会提取标记之间的 JSON。>>weboutEND<< - Viya(Web/JES):通过 /
parseSasViyaDebugResponse解析调试响应,将日志和 webout JSON 分离。parseSasViyaLogDebugResponse - Viya(Compute API):日志会从 compute session 中单独获取。
在所有情况下,启用调试并设置 后,都可以通过 获取 SAS 日志。
extraResponseAttributes: ['log']res.logRequest history
请求历史
Every executed request is appended to an in-memory history (capped at , default 10):
requestHistoryLimitts
sasjs.getSasRequests()
// SASjsRequest[]: { serviceLink, timestamp, sourceCode, generatedCode, logFile, SASWORK }sourceCodegeneratedCodedebug: true每个已执行的请求都会追加到内存中的历史记录中,其上限由 控制,默认值为 10:
requestHistoryLimitts
sasjs.getSasRequests()
// SASjsRequest[]: { serviceLink, timestamp, sourceCode, generatedCode, logFile, SASWORK }仅当 时, 和 才会包含数据。历史记录采用环形缓冲区;超过上限后,最旧的记录会被丢弃。
debug: truesourceCodegeneratedCodeAuthentication
身份验证
- SAS 9: (form-based against the stored process server). Session cookie is managed automatically.
sasjs.logIn(username, password) - Viya: OAuth client/secret (client credentials grant) or authorization code flow; tokens are refreshed automatically. Configure via CLI () for Node usage. For Node, pass
sasjs add cred(client/secret/access/refresh tokens) toauthConfig.request() - SASJS server: token-based auth against the sasjs/server API.
- SAS 9:,使用基于表单的方式针对已存储的 process server 进行身份验证。Session cookie 会自动管理。
sasjs.logIn(username, password) - Viya:支持 OAuth client/secret(client credentials grant)或 authorization code flow;token 会自动刷新。在 Node 中使用时,可通过 CLI()进行配置。在 Node 中调用
sasjs add cred时,可传入request()(client/secret/access/refresh token)。authConfig - SASJS 服务器:使用基于 token 的方式对 sasjs/server API 进行身份验证。
Key classes / modules
关键类/模块
- - main facade:
SASjs,request(),logIn()/logOut(),uploadFile(),executeScript(),startComputeJob()deployServicePack() - - HTTP layer; holds the request history (
RequestClient), CSRF tokens, and auth headersgetRequests() - - SAS 9 STP, Viya web JES, and SASjs server web (multipart form POST)
WebJobExecutor - - Viya compute API (direct code submission on a named context)
ComputeJobExecutor - - Viya JES API (job submission via the jobs API, not the web app)
JesJobExecutor - - SASjs server web execution
SasjsJobExecutor - - Viya compute session lifecycle
SessionManager - /
SASViyaApiClient/SAS9ApiClient- low-level per-platform clients (rarely needed directly)SASjsApiClient - utilities - file upload to SAS (binary content handling)
file/
- :主入口类(facade),提供
SASjs、request()、logIn()/logOut()、uploadFile()、executeScript()、startComputeJob()。deployServicePack() - :HTTP 层;保存请求历史(
RequestClient)、CSRF token 和身份验证请求头。getRequests() - :处理 SAS 9 STP、Viya Web JES 和 SASJS 服务器 Web 执行(multipart form POST)。
WebJobExecutor - :处理 Viya Compute API(在指定 context 上直接提交代码)。
ComputeJobExecutor - :处理 Viya JES API(通过 jobs API 提交作业,而不是使用 Web 应用)。
JesJobExecutor - :处理 SASJS 服务器 Web 执行。
SasjsJobExecutor - :管理 Viya compute session 的生命周期。
SessionManager - /
SASViyaApiClient/SAS9ApiClient:各平台底层客户端,通常无需直接使用。SASjsApiClient - 工具:向 SAS 上传文件(处理二进制内容)。
file/
Tips
提示
- Set to surface the SAS log in responses while developing.
debug: true - Always handle / error responses - SAS-side errors (e.g. from
response.status) come back in the JSON, not necessarily as HTTP errors.%mp_abort - For large payloads prefer CSV upload or streamed files over JSON input tables.
- Keep consistent with the
appLocinappLocused to deploy.sasjsconfig.json - Column names come back UPPERCASE from SAS. If your frontend expects lowercase, map them in JS rather than trying to force SAS casing.
- in a numeric input column becomes SAS missing (
null); empty string in a char column becomes empty string. Don't use.- validation rejects it.undefined
- 开发期间可设置 ,以便在响应中显示 SAS 日志。
debug: true - 始终处理 /错误响应。SAS 端错误(例如
response.status产生的错误)会出现在 JSON 中,不一定会作为 HTTP 错误返回。%mp_abort - 对于大型负载,应优先使用 CSV 上传或流式文件,而不是 JSON 输入表。
- 保持 与部署时使用的
appLoc中的sasjsconfig.json一致。appLoc - SAS 返回的列名为大写。如果前端需要小写列名,应在 JS 中进行映射,而不是尝试强制改变 SAS 的大小写。
- 数值输入列中的 会转换为 SAS 缺失值(
null);字符列中的空字符串会保持为空字符串。不要使用.,验证会直接拒绝该值。undefined
Using the adapter without a bundler (zero-build / strict CSP frontends)
不使用打包工具时使用 adapter(零构建/严格 CSP 前端)
The package root is a UMD bundle exposing a global . Pattern (from the minimal seed app):
index.jsSASjs- in package.json (runs on
"prepare": "cp node_modules/@sasjs/adapter/index.js src/sasjs.js").npm i - before your app script.
<script src="sasjs.js"></script> - Configure via a hidden custom element: and read attributes with
<sasjs serverType="SASJS" appLoc="/Public/app/myapp" debug="false"></sasjs>. When the app is streamed by SAS itself, omitdocument.querySelector('sasjs')- same-origin requests just work (CSPserverUrlsafe).default-src 'self'
包根目录下的 是一个暴露全局 的 UMD bundle。使用方式如下(来自最小种子应用):
index.jsSASjs- 在 package.json 中设置 (在执行
"prepare": "cp node_modules/@sasjs/adapter/index.js src/sasjs.js"时运行)。npm i - 在应用脚本之前添加 。
<script src="sasjs.js"></script> - 通过隐藏的自定义元素进行配置:,并使用
<sasjs serverType="SASJS" appLoc="/Public/app/myapp" debug="false"></sasjs>读取属性。当应用由 SAS 自身流式提供时,可以省略document.querySelector('sasjs')——同源请求可直接正常工作(CSPserverUrl安全)。default-src 'self'
Limitations
限制
This skill is a static reference for the @sasjs/adapter library - it provides guidance on the API, request/response shapes, authentication, and CSV serialization. It does not execute code, run shell commands, access the filesystem, connect to databases, or make network requests. All code examples are illustrative; the user must integrate them into their own application. References to authentication tokens describe what the adapter library manages at runtime - this skill does not read, write, or access those values itself.
本 skill 是 库的静态参考资料,用于提供 API、请求/响应结构、身份验证和 CSV 序列化方面的指导。它不会执行代码、运行 shell 命令、访问文件系统、连接数据库或发起网络请求。所有代码示例仅作说明,用户必须将其集成到自己的应用中。关于身份验证 token 的描述仅说明 adapter 库在运行时管理的功能;本 skill 本身不会读取、写入或访问这些值。
@sasjs/adapter