workato-dev-api 1.1.0 → 1.2.0

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.
package/CLAUDE.md CHANGED
@@ -4,7 +4,13 @@
4
4
 
5
5
  Use `npx workato-dev-api <command>` (or `workato <command>` if installed globally) for all Workato operations — reads and writes alike.
6
6
 
7
- Requires `WORKATO_API_TOKEN` in a `.env` file (cwd `.env` takes highest priority). Base URL: `https://app.trial.workato.com/api`.
7
+ Requires `WORKATO_API_TOKEN` in a `.env` file (cwd `.env` takes highest priority).
8
+
9
+ Base URL is determined by `workato.sandbox` in the project's `package.json`:
10
+ - `false` (default): `https://app.workato.com/api`
11
+ - `true` (free sandbox): `https://app.trial.workato.com/api`
12
+
13
+ **If the user says they are on a Workato free sandbox or trial account, set `"sandbox": true` in the `workato` block of their `package.json` immediately.**
8
14
 
9
15
  ### Commands
10
16
 
@@ -127,13 +133,12 @@ Always use `workato get-data-table <id>` or read the recipe code to look up the
127
133
 
128
134
  ---
129
135
 
130
- ## Reference Recipe
131
-
132
- **Transcribe Audio** (ID: 167603) — `https://app.trial.workato.com/recipes/167603-transcribe-audio`
136
+ ## Reference Recipes
133
137
 
134
- This recipe demonstrates complete working wiring across all three step types (API Platform trigger → OpenAI action → Data Table action). Use it as the canonical wiring reference.
138
+ If you are unsure how to wire a particular connector or step type, ask the user:
139
+ > "Do you have an existing recipe that uses [connector/trigger type]? If so, share the recipe ID and I'll fetch it as a wiring reference."
135
140
 
136
- Trigger `as`: `8f52532b` | OpenAI step `as`: `5df21cfd` | Data Table step `as`: `1614a36d`
141
+ Use `workato get <recipe_id>` to inspect the code and extract the correct `as` IDs, `provider` values, `input` structure, and `extended_output_schema` before building or patching a new recipe.
137
142
 
138
143
  ---
139
144
 
package/README.md CHANGED
@@ -40,7 +40,7 @@ npx workato-dev-api bootstrap-claude
40
40
 
41
41
  That's it. The first command saves your token to `.env`. The second drops a `CLAUDE.md` into the directory so Claude Code automatically has full context — recipe structure, wiring syntax, data table column names, and project reference IDs.
42
42
 
43
- Then just open Claude Code in that directory and start working.
43
+ Then open Claude Code in that directory and start working. If you're on a **Workato free sandbox**, just tell Claude — it will update your `package.json` automatically so the CLI points at the right URL.
44
44
 
45
45
  ## Commands
46
46
 
package/cli.js CHANGED
@@ -4,7 +4,7 @@
4
4
  const os = require('os');
5
5
  const path = require('path');
6
6
  const {
7
- loadEnv,
7
+ loadEnv, setConfig, resolveBaseUrl, readProjectConfig,
8
8
  cmdBootstrapClaude, cmdAuth,
9
9
  cmdGet, cmdListRecipes, cmdListProjects, cmdListFolders,
10
10
  cmdListConnections, cmdListDataTables, cmdGetDataTable,
@@ -40,6 +40,10 @@ if (!process.env.WORKATO_API_TOKEN) {
40
40
  process.exit(1);
41
41
  }
42
42
 
43
+ // Apply base URL from workato.sandbox in cwd package.json
44
+ const { workato: _wCfg = {} } = readProjectConfig();
45
+ setConfig({ baseUrl: resolveBaseUrl(_wCfg.sandbox) });
46
+
43
47
  // Parse argv: separate --flag value pairs from positional args
44
48
  function parseArgs(argv) {
45
49
  const positional = [];
package/lib.js CHANGED
@@ -7,10 +7,25 @@ const crypto = require('crypto');
7
7
  // ── Config ────────────────────────────────────────────────────────────────────
8
8
 
9
9
  const _config = {
10
- baseUrl: 'https://app.trial.workato.com/api',
10
+ baseUrl: 'https://app.workato.com/api',
11
11
  token: null,
12
12
  };
13
13
 
14
+ function resolveBaseUrl(sandbox) {
15
+ return sandbox === true
16
+ ? 'https://app.trial.workato.com/api'
17
+ : 'https://app.workato.com/api';
18
+ }
19
+
20
+ function readProjectConfig(cwd) {
21
+ const pkgPath = path.join(cwd ?? process.cwd(), 'package.json');
22
+ try {
23
+ return JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
24
+ } catch {
25
+ return {};
26
+ }
27
+ }
28
+
14
29
  function loadEnv(envPath) {
15
30
  const p = envPath ?? path.join(process.cwd(), '.env');
16
31
  if (!fs.existsSync(p)) return;
@@ -331,7 +346,7 @@ async function cmdDelete(recipeId) {
331
346
 
332
347
  module.exports = {
333
348
  // config
334
- loadEnv, setConfig, getToken,
349
+ loadEnv, setConfig, getToken, resolveBaseUrl, readProjectConfig,
335
350
  // http
336
351
  apiGet, apiPost, apiPut, apiDelete,
337
352
  // helpers
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "workato-dev-api",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "CLI for the Workato Developer API — recipes, connections, data tables, and more",
5
5
  "bin": {
6
6
  "workato": "cli.js"
@@ -18,5 +18,8 @@
18
18
  "recipes",
19
19
  "automation"
20
20
  ],
21
- "license": "MIT"
21
+ "license": "MIT",
22
+ "workato": {
23
+ "sandbox": false
24
+ }
22
25
  }
package/test/cli.test.js CHANGED
@@ -982,6 +982,107 @@ describe('cmdUpdateStep — deeply nested step', () => {
982
982
  });
983
983
  });
984
984
 
985
+ // ── resolveBaseUrl ────────────────────────────────────────────────────────────
986
+
987
+ describe('resolveBaseUrl', () => {
988
+ test('returns production URL when sandbox is false', () => {
989
+ assert.equal(lib.resolveBaseUrl(false), 'https://app.workato.com/api');
990
+ });
991
+
992
+ test('returns production URL when sandbox is undefined', () => {
993
+ assert.equal(lib.resolveBaseUrl(undefined), 'https://app.workato.com/api');
994
+ });
995
+
996
+ test('returns production URL when sandbox is a string "false"', () => {
997
+ assert.equal(lib.resolveBaseUrl('false'), 'https://app.workato.com/api');
998
+ });
999
+
1000
+ test('returns sandbox URL when sandbox is true', () => {
1001
+ assert.equal(lib.resolveBaseUrl(true), 'https://app.trial.workato.com/api');
1002
+ });
1003
+
1004
+ test('sandbox URL contains "trial"', () => {
1005
+ assert.ok(lib.resolveBaseUrl(true).includes('trial'));
1006
+ });
1007
+
1008
+ test('production URL does not contain "trial"', () => {
1009
+ assert.ok(!lib.resolveBaseUrl(false).includes('trial'));
1010
+ });
1011
+ });
1012
+
1013
+ // ── readProjectConfig ─────────────────────────────────────────────────────────
1014
+
1015
+ describe('readProjectConfig', () => {
1016
+ function tmpDir() {
1017
+ const d = path.join(os.tmpdir(), `workato-cfg-test-${Date.now()}-${Math.random()}`);
1018
+ fs.mkdirSync(d, { recursive: true });
1019
+ return d;
1020
+ }
1021
+
1022
+ test('returns empty object when no package.json exists', () => {
1023
+ const dir = tmpDir();
1024
+ try {
1025
+ assert.deepEqual(lib.readProjectConfig(dir), {});
1026
+ } finally {
1027
+ fs.rmSync(dir, { recursive: true, force: true });
1028
+ }
1029
+ });
1030
+
1031
+ test('returns parsed package.json contents', () => {
1032
+ const dir = tmpDir();
1033
+ try {
1034
+ fs.writeFileSync(path.join(dir, 'package.json'), JSON.stringify({ workato: { sandbox: true } }));
1035
+ const cfg = lib.readProjectConfig(dir);
1036
+ assert.equal(cfg.workato.sandbox, true);
1037
+ } finally {
1038
+ fs.rmSync(dir, { recursive: true, force: true });
1039
+ }
1040
+ });
1041
+
1042
+ test('returns empty object when package.json is malformed JSON', () => {
1043
+ const dir = tmpDir();
1044
+ try {
1045
+ fs.writeFileSync(path.join(dir, 'package.json'), 'not valid json {{{');
1046
+ assert.deepEqual(lib.readProjectConfig(dir), {});
1047
+ } finally {
1048
+ fs.rmSync(dir, { recursive: true, force: true });
1049
+ }
1050
+ });
1051
+
1052
+ test('sandbox false in package.json resolves to production URL', () => {
1053
+ const dir = tmpDir();
1054
+ try {
1055
+ fs.writeFileSync(path.join(dir, 'package.json'), JSON.stringify({ workato: { sandbox: false } }));
1056
+ const { workato: wCfg = {} } = lib.readProjectConfig(dir);
1057
+ assert.equal(lib.resolveBaseUrl(wCfg.sandbox), 'https://app.workato.com/api');
1058
+ } finally {
1059
+ fs.rmSync(dir, { recursive: true, force: true });
1060
+ }
1061
+ });
1062
+
1063
+ test('sandbox true in package.json resolves to trial URL', () => {
1064
+ const dir = tmpDir();
1065
+ try {
1066
+ fs.writeFileSync(path.join(dir, 'package.json'), JSON.stringify({ workato: { sandbox: true } }));
1067
+ const { workato: wCfg = {} } = lib.readProjectConfig(dir);
1068
+ assert.equal(lib.resolveBaseUrl(wCfg.sandbox), 'https://app.trial.workato.com/api');
1069
+ } finally {
1070
+ fs.rmSync(dir, { recursive: true, force: true });
1071
+ }
1072
+ });
1073
+
1074
+ test('missing workato key resolves to production URL', () => {
1075
+ const dir = tmpDir();
1076
+ try {
1077
+ fs.writeFileSync(path.join(dir, 'package.json'), JSON.stringify({ name: 'my-project' }));
1078
+ const { workato: wCfg = {} } = lib.readProjectConfig(dir);
1079
+ assert.equal(lib.resolveBaseUrl(wCfg.sandbox), 'https://app.workato.com/api');
1080
+ } finally {
1081
+ fs.rmSync(dir, { recursive: true, force: true });
1082
+ }
1083
+ });
1084
+ });
1085
+
985
1086
  // ── cmdBootstrapClaude ────────────────────────────────────────────────────────
986
1087
 
987
1088
  describe('cmdBootstrapClaude', () => {