adfinem 0.0.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/.env.example +13 -0
  2. package/CHANGELOG.md +17 -0
  3. package/CODE_OF_CONDUCT.md +21 -0
  4. package/CONTRIBUTING.md +29 -0
  5. package/LICENSE +21 -0
  6. package/README.md +97 -3
  7. package/SECURITY.md +13 -0
  8. package/catalogs/.gitkeep +0 -0
  9. package/catalogs/api-operations.yaml +21 -0
  10. package/catalogs/batches.yaml +74 -0
  11. package/catalogs/queries.yaml +75 -0
  12. package/config/environments.yaml +13 -0
  13. package/dist/actions/assert-db.js +3 -0
  14. package/dist/actions/run-eod.js +3 -0
  15. package/dist/adapters/api/api-collections.js +296 -0
  16. package/dist/adapters/api/body-utils.js +9 -0
  17. package/dist/adapters/api/rest-client.js +557 -0
  18. package/dist/adapters/api/soap-client.js +5 -0
  19. package/dist/adapters/db/assertions.js +87 -0
  20. package/dist/adapters/db/oracle-client.js +115 -0
  21. package/dist/adapters/db/query-catalog.js +75 -0
  22. package/dist/adapters/unix/batch-catalog.js +71 -0
  23. package/dist/adapters/unix/batch-input-files.js +36 -0
  24. package/dist/adapters/unix/batch-runner.js +382 -0
  25. package/dist/adapters/unix/ssh-client.js +228 -0
  26. package/dist/app/server.js +827 -0
  27. package/dist/cli.js +516 -0
  28. package/dist/config/environments.js +138 -0
  29. package/dist/config/registry.js +18 -0
  30. package/dist/config/secrets.js +123 -0
  31. package/dist/dsl/parser.js +20 -0
  32. package/dist/dsl/schema.js +182 -0
  33. package/dist/dsl/types.js +1 -0
  34. package/dist/dsl/validator.js +264 -0
  35. package/dist/engine/captures.js +68 -0
  36. package/dist/engine/context.js +69 -0
  37. package/dist/engine/evidence.js +33 -0
  38. package/dist/engine/known-errors.js +129 -0
  39. package/dist/engine/retry.js +13 -0
  40. package/dist/engine/runner.js +710 -0
  41. package/dist/engine/step-result.js +58 -0
  42. package/dist/flows/catalog-normalizer.js +72 -0
  43. package/dist/flows/compiler.js +237 -0
  44. package/dist/flows/concat.js +130 -0
  45. package/dist/flows/parser.js +21 -0
  46. package/dist/flows/schema.js +142 -0
  47. package/dist/flows/types.js +1 -0
  48. package/dist/flows/validator.js +470 -0
  49. package/dist/reports/html-report.js +112 -0
  50. package/dist/reports/junit-report.js +48 -0
  51. package/docs/.gitkeep +0 -0
  52. package/docs/DB_UNIX_OPERATIONS.md +118 -0
  53. package/docs/FLOW_BUILDER.md +87 -0
  54. package/flows/account_processing_cycle.flow.yaml +88 -0
  55. package/flows/new_flow.flow.yaml +22 -0
  56. package/package.json +98 -11
  57. package/scenarios/smoke/account-processing-smoke.yaml +44 -0
  58. package/scenarios/smoke/api-db-batch-check.yaml +40 -0
  59. package/src/actions/assert-db.ts +6 -0
  60. package/src/actions/run-eod.ts +6 -0
  61. package/src/adapters/api/api-collections.ts +375 -0
  62. package/src/adapters/api/body-utils.ts +10 -0
  63. package/src/adapters/api/rest-client.ts +587 -0
  64. package/src/adapters/api/soap-client.ts +7 -0
  65. package/src/adapters/db/assertions.ts +83 -0
  66. package/src/adapters/db/oracle-client.ts +133 -0
  67. package/src/adapters/db/query-catalog.ts +80 -0
  68. package/src/adapters/unix/batch-catalog.ts +81 -0
  69. package/src/adapters/unix/batch-input-files.ts +39 -0
  70. package/src/adapters/unix/batch-runner.ts +456 -0
  71. package/src/adapters/unix/ssh-client.ts +248 -0
  72. package/src/app/server.ts +914 -0
  73. package/src/cli.ts +517 -0
  74. package/src/config/environments.ts +193 -0
  75. package/src/config/registry.ts +23 -0
  76. package/src/config/secrets.ts +128 -0
  77. package/src/dsl/parser.ts +24 -0
  78. package/src/dsl/schema.ts +189 -0
  79. package/src/dsl/types.ts +371 -0
  80. package/src/dsl/validator.ts +282 -0
  81. package/src/engine/captures.ts +66 -0
  82. package/src/engine/context.ts +76 -0
  83. package/src/engine/evidence.ts +35 -0
  84. package/src/engine/known-errors.ts +145 -0
  85. package/src/engine/retry.ts +11 -0
  86. package/src/engine/runner.ts +746 -0
  87. package/src/engine/step-result.ts +64 -0
  88. package/src/flows/catalog-normalizer.ts +86 -0
  89. package/src/flows/compiler.ts +247 -0
  90. package/src/flows/concat.ts +149 -0
  91. package/src/flows/parser.ts +27 -0
  92. package/src/flows/schema.ts +154 -0
  93. package/src/flows/types.ts +130 -0
  94. package/src/flows/validator.ts +468 -0
  95. package/src/llm/system-prompt.md +9 -0
  96. package/src/reports/html-report.ts +113 -0
  97. package/src/reports/junit-report.ts +55 -0
  98. package/src/types/oracledb.d.ts +1 -0
  99. package/templates/.gitkeep +0 -0
  100. package/templates/api/create-test-case.json +5 -0
  101. package/templates/api/record-test-activity.json +6 -0
  102. package/tsconfig.json +15 -0
  103. package/vite.config.ts +17 -0
  104. package/web/index.html +12 -0
  105. package/web/src/App.tsx +6588 -0
  106. package/web/src/main.tsx +10 -0
  107. package/web/src/styles.css +3147 -0
  108. package/web-dist/assets/elk.bundled-ChwRCIWJ.js +24 -0
  109. package/web-dist/assets/index-CArbX4zm.css +1 -0
  110. package/web-dist/assets/index-vDCbj8xB.js +28 -0
  111. package/web-dist/index.html +13 -0
  112. package/index.js +0 -1
@@ -0,0 +1,118 @@
1
+ # Database and Unix Operations
2
+
3
+ ## Purpose
4
+
5
+ Adfinem supports Action Library-driven database and Unix batch steps inside the same scenario engine as API operations.
6
+
7
+ Scenarios do not carry arbitrary SQL or shell commands. They reference allowlisted Action Library templates:
8
+
9
+ - `catalogs/queries.yaml`
10
+ - `catalogs/batches.yaml`
11
+
12
+ This keeps generated or hand-authored scenarios executable but bounded.
13
+
14
+ ## Database Queries
15
+
16
+ Use `db_assert` when the query has an `expect` block and must pass or fail the scenario.
17
+
18
+ ```yaml
19
+ - id: assert_activity
20
+ action: db_assert
21
+ via: db
22
+ query: test_activity_exists
23
+ params:
24
+ case_id: "${case_id}"
25
+ amount: 100.00
26
+ ```
27
+
28
+ Use `db_query` when the query is meant to retrieve values for later steps.
29
+
30
+ ```yaml
31
+ - id: load_case
32
+ action: db_query
33
+ via: db
34
+ query: case_by_external_id
35
+ params:
36
+ external_id: "CASE-1001"
37
+ ```
38
+
39
+ Direct CLI checks:
40
+
41
+ ```powershell
42
+ npm run adfinem -- db-query test_activity_exists --env local --params "{\"case_id\":\"CASE-1001\",\"amount\":111}"
43
+ npm run adfinem -- db-assert test_activity_exists --env local --params "{\"case_id\":\"CASE-1001\",\"amount\":111}"
44
+ ```
45
+
46
+ ## Unix Batches
47
+
48
+ Batch templates define the SSH host, command, arguments, timeout, success criteria, and optional captures.
49
+
50
+ ```yaml
51
+ daily_processing:
52
+ hostRef: qa_worker
53
+ command: "run_daily_processing.sh"
54
+ args:
55
+ - name: processing_date
56
+ required: true
57
+ pattern: "^\\d{4}-\\d{2}-\\d{2}$"
58
+ timeoutSeconds: 3600
59
+ success:
60
+ exitCodes: [0]
61
+ requiredOutput:
62
+ - "SUCCESS"
63
+ captures:
64
+ daily_processing_exit_code: "$.exitCode"
65
+ ```
66
+
67
+ Scenario step:
68
+
69
+ ```yaml
70
+ - id: run_processing
71
+ action: unix_batch
72
+ via: unix
73
+ batch: daily_processing
74
+ params:
75
+ processing_date: "${processing_date}"
76
+ retry:
77
+ attempts: 2
78
+ delaySeconds: 30
79
+ ```
80
+
81
+ Direct CLI check:
82
+
83
+ ```powershell
84
+ npm run adfinem -- run-batch daily_processing --env local --params "{\"processing_date\":\"2026-04-27\"}" --attempts 2 --delay-seconds 30
85
+ ```
86
+
87
+ ## Captures
88
+
89
+ Database and Unix steps can capture values into scenario context. Later steps can use them as `${name}`.
90
+
91
+ Supported capture expressions:
92
+
93
+ - JSONPath: `$.rows[0].CNT`, `$.stdout`, `$.exitCode`
94
+ - Simple property path: `rowCount`, `stdout`, `exitCode`
95
+ - Literal: `literal:some-value`
96
+ - Regex: `regex:$.stdout:Case=(\\d+)`
97
+
98
+ If a capture expression does not match, the step fails. This is intentional so data passing bugs are visible.
99
+
100
+ ## Environment
101
+
102
+ `config/environments.yaml` maps environment names to database and SSH connection settings. Values usually come from `.env`:
103
+
104
+ ```text
105
+ ADFINEM_DB_USER=
106
+ ADFINEM_DB_PASSWORD=
107
+ ADFINEM_DB_CONNECT_STRING=
108
+ ADFINEM_SSH_QA_WORKER_HOST=
109
+ ADFINEM_SSH_USER=
110
+ ADFINEM_SSH_PASSWORD=
111
+ ADFINEM_SSH_PRIVATE_KEY_PATH=
112
+ ```
113
+
114
+ ## Evidence
115
+
116
+ Each database step writes `<step>.db.json`.
117
+
118
+ Each Unix step writes `<step>.unix.json`, and when captures exist, `<step>.unix-captures.json`.
@@ -0,0 +1,87 @@
1
+ # Flow Builder
2
+
3
+ ## Purpose
4
+
5
+ Flows are the durable source of truth for chained API, database, and Unix automation. They let you combine cataloged API operations with database queries, assertions, Unix batches, and captured output mappings without typing long CLI command chains.
6
+
7
+ Flow files live under `flows/` and use the suffix `.flow.yaml`.
8
+
9
+ ## Concepts
10
+
11
+ - **API operation**: an allowlisted operation from `catalogs/api-operations.yaml`.
12
+ - **Action**: a technical step such as `db_query`, `db_assert`, `db_execute`, or `unix_batch`.
13
+ - **Post action**: an action attached to an API operation and executed immediately after it.
14
+ - **Output mapping**: later steps reference previous outputs with `${node_id.capture_name}`.
15
+
16
+ The compatibility folder is still named `catalogs/`; those files are the Action Library.
17
+
18
+ ## CLI
19
+
20
+ Validate a flow:
21
+
22
+ ```powershell
23
+ npm run adfinem -- validate-flow flows\account_processing_cycle.flow.yaml
24
+ ```
25
+
26
+ Compile a flow to the scenario structure:
27
+
28
+ ```powershell
29
+ npm run adfinem -- compile-flow flows\account_processing_cycle.flow.yaml --output evidence\compiled-flow.json
30
+ ```
31
+
32
+ Dry run a flow:
33
+
34
+ ```powershell
35
+ npm run adfinem -- run-flow flows\account_processing_cycle.flow.yaml --env local --dry-run
36
+ ```
37
+
38
+ Execute a flow:
39
+
40
+ ```powershell
41
+ npm run adfinem -- run-flow flows\account_processing_cycle.flow.yaml --env local
42
+ ```
43
+
44
+ Create a new flow by concatenating existing flows:
45
+
46
+ ```powershell
47
+ npm run adfinem -- concat-flows flows\combined.flow.yaml flows\first.flow.yaml flows\second.flow.yaml --id combined --name "Combined flow"
48
+ ```
49
+
50
+ The concat command preserves the internal order of each input flow, connects the last top-level node of one flow to the first top-level node of the next flow, merges variables, and rewrites node references if ids collide.
51
+
52
+ ## Local App
53
+
54
+ Start the app:
55
+
56
+ ```powershell
57
+ npm run app
58
+ ```
59
+
60
+ Open:
61
+
62
+ ```text
63
+ http://localhost:4177
64
+ ```
65
+
66
+ The app saves the same flow files used by the CLI. It can load API operations, database templates, Unix batches, validate flows, and start runs through the local backend.
67
+
68
+ ### Workbench Features
69
+
70
+ - Delete saved workflows from the Flows explorer. The app removes the matching `flows/*.flow.yaml` file after confirmation.
71
+ - Import Postman collection JSON files from **API Collections**. Imported collections are stored locally in `catalogs/api-collections.json` and exposed as grouped request templates instead of flooding the sidebar.
72
+ - Click an imported collection to search requests by folder, method, name, or path, then add one or multiple requests to the workflow.
73
+ - API request steps are editable per workflow. Method, path, headers, query params, body, auth, inputs, captures, assertions, and accepted statuses can diverge from the imported template without changing the source collection.
74
+ - Import Postman environment JSON files from the top bar. Variables are copied into the selected workflow/environment input set.
75
+ - Use insert controls, drag/drop, move, duplicate, disable, and section labels to organize the workflow timeline.
76
+ - Recent run history is read from `evidence/*/run-result.json` and shown per workflow.
77
+
78
+ ## Evidence
79
+
80
+ Each `run-flow` execution writes:
81
+
82
+ - `run-result.json`
83
+ - the original `flow.yaml`
84
+ - `compiled-flow.json`
85
+ - per-step input/evidence files
86
+ - `report.html`
87
+ - `junit.xml`
@@ -0,0 +1,88 @@
1
+ version: 1
2
+ id: account_processing_cycle
3
+ name: Account processing cycle
4
+ environment: local
5
+ variables:
6
+ processing_date: "2026-04-27"
7
+ nodes:
8
+ - id: create_case
9
+ label: Create test case
10
+ type: api_operation
11
+ operation: create_test_case
12
+ input:
13
+ tenant: demo
14
+ external_id: CASE-3001
15
+ case_type: account-processing
16
+ capture:
17
+ case_id: $.case.id
18
+ case_status: $.case.status
19
+ - id: record_activity
20
+ label: Record test activity
21
+ type: api_operation
22
+ operation: record_test_activity
23
+ input:
24
+ case_id: ${create_case.case_id}
25
+ amount: 100
26
+ currency: USD
27
+ activity_type: adjustment
28
+ capture:
29
+ activity_id: $.activity.id
30
+ activity_status: $.activity.status
31
+ - id: assert_activity
32
+ label: Assert activity exists
33
+ type: db_assert
34
+ query: test_activity_exists
35
+ params:
36
+ case_id: ${create_case.case_id}
37
+ amount: 100
38
+ - id: processing_loop
39
+ label: Processing loop
40
+ type: loop
41
+ loop:
42
+ mode: count
43
+ count: 2
44
+ itemName: run
45
+ maxIterations: 10
46
+ dateCursor:
47
+ outputName: processing_date
48
+ start: ${processing_date}
49
+ inputFormat: YYYY-MM-DD
50
+ outputFormat: YYYY-MM-DD
51
+ advance:
52
+ mode: days
53
+ amount: 1
54
+ nodes:
55
+ - id: run_processing
56
+ label: Run daily processing
57
+ type: unix_batch
58
+ batch: daily_processing
59
+ params:
60
+ processing_date: ${processing_loop.processing_date}
61
+ - id: assert_processing
62
+ label: Assert processing balanced
63
+ type: db_assert
64
+ query: processing_balanced
65
+ params:
66
+ case_id: ${create_case.case_id}
67
+ processing_date: ${processing_loop.processing_date}
68
+ edges:
69
+ - from: create_case
70
+ to: record_activity
71
+ - from: record_activity
72
+ to: assert_activity
73
+ - from: assert_activity
74
+ to: processing_loop
75
+ ui:
76
+ positions:
77
+ create_case:
78
+ x: -360
79
+ y: 0
80
+ record_activity:
81
+ x: -160
82
+ y: 180
83
+ assert_activity:
84
+ x: 60
85
+ y: 360
86
+ processing_loop:
87
+ x: 340
88
+ y: 520
@@ -0,0 +1,22 @@
1
+ version: 1
2
+ id: new_flow
3
+ name: New flow
4
+ environment: local
5
+ variables: {}
6
+ nodes:
7
+ - id: import_transactions
8
+ label: Import transactions
9
+ params:
10
+ transactions_file:
11
+ fileName: transactions.csv
12
+ localPath: data/batch-input-files/new_flow/import_transactions/transactions_file/transactions.csv
13
+ sizeBytes: 128
14
+ remotePath: /tmp/adfinem/inbox/
15
+ type: unix_batch
16
+ batch: import_transactions
17
+ edges: []
18
+ ui:
19
+ positions:
20
+ import_transactions:
21
+ x: 18
22
+ y: -150
package/package.json CHANGED
@@ -1,11 +1,98 @@
1
- {
2
- "name": "adfinem",
3
- "version": "0.0.0",
4
- "description": "Adfinem Open Source Project.",
5
- "main": "index.js",
6
- "files": [
7
- "index.js",
8
- "README.md"
9
- ],
10
- "license": "MIT"
11
- }
1
+ {
2
+ "name": "adfinem",
3
+ "version": "0.1.1",
4
+ "description": "Open-source QA test helper for deterministic API, database, Unix, and workflow automation",
5
+ "keywords": [
6
+ "qa",
7
+ "testing",
8
+ "api",
9
+ "database",
10
+ "unix",
11
+ "workflow",
12
+ "automation",
13
+ "cli"
14
+ ],
15
+ "author": "Adfinem contributors",
16
+ "license": "MIT",
17
+ "private": false,
18
+ "homepage": "https://github.com/amnotabot/adfinem#readme",
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/amnotabot/adfinem.git"
22
+ },
23
+ "bugs": {
24
+ "url": "https://github.com/amnotabot/adfinem/issues"
25
+ },
26
+ "type": "module",
27
+ "bin": {
28
+ "adfinem": "dist/cli.js"
29
+ },
30
+ "files": [
31
+ "dist",
32
+ "src",
33
+ "web",
34
+ "web-dist",
35
+ "catalogs",
36
+ "config",
37
+ "flows",
38
+ "scenarios",
39
+ "templates",
40
+ "docs",
41
+ ".env.example",
42
+ "README.md",
43
+ "LICENSE",
44
+ "CHANGELOG.md",
45
+ "CONTRIBUTING.md",
46
+ "CODE_OF_CONDUCT.md",
47
+ "SECURITY.md",
48
+ "tsconfig.json",
49
+ "vite.config.ts"
50
+ ],
51
+ "engines": {
52
+ "node": ">=20"
53
+ },
54
+ "publishConfig": {
55
+ "access": "public"
56
+ },
57
+ "scripts": {
58
+ "build": "tsc -p tsconfig.json",
59
+ "adfinem": "tsx src/cli.ts",
60
+ "cli": "tsx src/cli.ts",
61
+ "test": "tsx --test tests/api-only.test.ts",
62
+ "check": "npm run build && npm test",
63
+ "validate": "tsx src/cli.ts validate scenarios/smoke/account-processing-smoke.yaml",
64
+ "smoke:dry": "tsx src/cli.ts run scenarios/smoke/account-processing-smoke.yaml --env local --dry-run",
65
+ "web:build": "vite build",
66
+ "app": "npm run web:build && tsx src/app/server.ts",
67
+ "package:dry-run": "npm pack --dry-run --json",
68
+ "release:validate": "npm run check && npm run web:build && npm run validate && npm run smoke:dry && npm run package:dry-run",
69
+ "prepublishOnly": "npm run release:validate"
70
+ },
71
+ "dependencies": {
72
+ "@xyflow/react": "^12.10.2",
73
+ "axios": "^1.9.0",
74
+ "commander": "^12.1.0",
75
+ "dotenv": "^16.4.7",
76
+ "elkjs": "^0.11.1",
77
+ "jsonpath-plus": "^10.3.0",
78
+ "lucide-react": "^1.14.0",
79
+ "react": "^19.2.5",
80
+ "react-dom": "^19.2.5",
81
+ "ssh2": "^1.16.0",
82
+ "yaml": "^2.7.1",
83
+ "zod": "^3.24.3"
84
+ },
85
+ "devDependencies": {
86
+ "@types/node": "^20.17.31",
87
+ "@types/react": "^19.2.14",
88
+ "@types/react-dom": "^19.2.3",
89
+ "@types/ssh2": "^1.15.5",
90
+ "@vitejs/plugin-react": "^6.0.1",
91
+ "tsx": "^4.19.4",
92
+ "typescript": "^5.8.3",
93
+ "vite": "^8.0.10"
94
+ },
95
+ "optionalDependencies": {
96
+ "oracledb": "^6.8.0"
97
+ }
98
+ }
@@ -0,0 +1,44 @@
1
+ id: account_processing_smoke
2
+ environment: local
3
+ variables:
4
+ processing_date: "2026-04-27"
5
+ steps:
6
+ - id: create_case
7
+ action: create_test_case
8
+ via: api
9
+ input:
10
+ tenant: "demo"
11
+ external_id: "CASE-1001"
12
+ case_type: "account-processing"
13
+
14
+ - id: record_activity
15
+ action: record_test_activity
16
+ via: api
17
+ input:
18
+ case_id: "${case_id}"
19
+ amount: 100.00
20
+ currency: "USD"
21
+ activity_type: "adjustment"
22
+
23
+ - id: assert_activity
24
+ action: db_assert
25
+ via: db
26
+ query: test_activity_exists
27
+ params:
28
+ case_id: "${case_id}"
29
+ amount: 100.00
30
+
31
+ - id: run_processing
32
+ action: unix_batch
33
+ via: unix
34
+ batch: daily_processing
35
+ params:
36
+ processing_date: "${processing_date}"
37
+
38
+ - id: assert_processing
39
+ action: db_assert
40
+ via: db
41
+ query: processing_balanced
42
+ params:
43
+ case_id: "${case_id}"
44
+ processing_date: "${processing_date}"
@@ -0,0 +1,40 @@
1
+ id: api_db_batch_check
2
+ environment: local
3
+ variables:
4
+ processing_date: "2026-04-27"
5
+
6
+ steps:
7
+ - id: create_case
8
+ action: create_test_case
9
+ via: api
10
+ input:
11
+ tenant: "demo"
12
+ external_id: "CASE-2001"
13
+ case_type: "api-db-batch"
14
+
15
+ - id: record_activity
16
+ action: record_test_activity
17
+ via: api
18
+ input:
19
+ case_id: "${case_id}"
20
+ amount: 111
21
+ currency: "USD"
22
+ activity_type: "posting"
23
+
24
+ - id: run_processing
25
+ action: unix_batch
26
+ via: unix
27
+ batch: daily_processing
28
+ params:
29
+ processing_date: "${processing_date}"
30
+ retry:
31
+ attempts: 2
32
+ delaySeconds: 30
33
+
34
+ - id: assert_processing
35
+ action: db_assert
36
+ via: db
37
+ query: processing_balanced
38
+ params:
39
+ case_id: "${case_id}"
40
+ processing_date: "${processing_date}"
@@ -0,0 +1,6 @@
1
+ import type { QueryCatalogEntry } from "../dsl/types.js";
2
+ import { OracleClient } from "../adapters/db/oracle-client.js";
3
+
4
+ export async function assertDb(oracle: OracleClient, entry: QueryCatalogEntry, params: Record<string, unknown>) {
5
+ return await oracle.assert(entry, params);
6
+ }
@@ -0,0 +1,6 @@
1
+ import type { BatchCatalogEntry } from "../dsl/types.js";
2
+ import { BatchRunner, type BatchRunOptions } from "../adapters/unix/batch-runner.js";
3
+
4
+ export async function runBatch(batchRunner: BatchRunner, entry: BatchCatalogEntry, params: Record<string, unknown>, options?: BatchRunOptions) {
5
+ return await batchRunner.run(entry, params, options);
6
+ }