workato-dev-api 1.0.1 → 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 +11 -6
- package/README.md +6 -2
- package/cli.js +21 -9
- package/lib.js +43 -2
- package/package.json +5 -2
- package/test/cli.test.js +239 -0
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).
|
|
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
|
|
131
|
-
|
|
132
|
-
**Transcribe Audio** (ID: 167603) — `https://app.trial.workato.com/recipes/167603-transcribe-audio`
|
|
136
|
+
## Reference Recipes
|
|
133
137
|
|
|
134
|
-
|
|
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
|
-
|
|
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
|
@@ -31,13 +31,16 @@ You can also export it directly in your shell environment.
|
|
|
31
31
|
|
|
32
32
|
## Claude Code setup
|
|
33
33
|
|
|
34
|
-
In a clean working directory, run
|
|
34
|
+
In a clean working directory, run these two commands once before starting Claude Code:
|
|
35
35
|
|
|
36
36
|
```sh
|
|
37
|
+
npx workato-dev-api auth YOUR_API_TOKEN
|
|
37
38
|
npx workato-dev-api bootstrap-claude
|
|
38
39
|
```
|
|
39
40
|
|
|
40
|
-
|
|
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
|
+
|
|
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.
|
|
41
44
|
|
|
42
45
|
## Commands
|
|
43
46
|
|
|
@@ -46,6 +49,7 @@ This writes a `CLAUDE.md` with full context — recipe code structure, wiring sy
|
|
|
46
49
|
| Command | Description |
|
|
47
50
|
|---|---|
|
|
48
51
|
| `workato bootstrap-claude` | Copy `CLAUDE.md` into the current directory |
|
|
52
|
+
| `workato auth <token>` | Save your API token to `.env` in the current directory |
|
|
49
53
|
|
|
50
54
|
### Read
|
|
51
55
|
|
package/cli.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
const fs = require('fs');
|
|
5
4
|
const os = require('os');
|
|
6
5
|
const path = require('path');
|
|
7
6
|
const {
|
|
8
|
-
loadEnv,
|
|
7
|
+
loadEnv, setConfig, resolveBaseUrl, readProjectConfig,
|
|
8
|
+
cmdBootstrapClaude, cmdAuth,
|
|
9
9
|
cmdGet, cmdListRecipes, cmdListProjects, cmdListFolders,
|
|
10
10
|
cmdListConnections, cmdListDataTables, cmdGetDataTable,
|
|
11
11
|
cmdGetJobs, cmdGetJob,
|
|
@@ -13,12 +13,19 @@ const {
|
|
|
13
13
|
cmdStart, cmdStop, cmdDelete,
|
|
14
14
|
} = require('./lib');
|
|
15
15
|
|
|
16
|
-
//
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
// Setup commands run before env/token setup
|
|
17
|
+
const _setupCmd = process.argv[2];
|
|
18
|
+
if (_setupCmd === 'bootstrap-claude') {
|
|
19
|
+
cmdBootstrapClaude(process.cwd());
|
|
20
|
+
process.exit(0);
|
|
21
|
+
}
|
|
22
|
+
if (_setupCmd === 'auth') {
|
|
23
|
+
const token = process.argv[3];
|
|
24
|
+
if (!token) {
|
|
25
|
+
console.error('Usage: workato auth <token>');
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
cmdAuth(token, process.cwd());
|
|
22
29
|
process.exit(0);
|
|
23
30
|
}
|
|
24
31
|
|
|
@@ -29,10 +36,14 @@ loadEnv(path.join(os.homedir(), '.env'));
|
|
|
29
36
|
loadEnv(path.join(process.cwd(), '.env'));
|
|
30
37
|
|
|
31
38
|
if (!process.env.WORKATO_API_TOKEN) {
|
|
32
|
-
console.error('Error: WORKATO_API_TOKEN not set.\
|
|
39
|
+
console.error('Error: WORKATO_API_TOKEN not set.\nRun: workato auth <your_token>\nOr create a .env file with: WORKATO_API_TOKEN=your_token_here');
|
|
33
40
|
process.exit(1);
|
|
34
41
|
}
|
|
35
42
|
|
|
43
|
+
// Apply base URL from workato.sandbox in cwd package.json
|
|
44
|
+
const { workato: _wCfg = {} } = readProjectConfig();
|
|
45
|
+
setConfig({ baseUrl: resolveBaseUrl(_wCfg.sandbox) });
|
|
46
|
+
|
|
36
47
|
// Parse argv: separate --flag value pairs from positional args
|
|
37
48
|
function parseArgs(argv) {
|
|
38
49
|
const positional = [];
|
|
@@ -61,6 +72,7 @@ workato <command> [options]
|
|
|
61
72
|
|
|
62
73
|
Setup:
|
|
63
74
|
bootstrap-claude Copy CLAUDE.md into the current directory
|
|
75
|
+
auth <token> Save API token to .env in the current directory
|
|
64
76
|
|
|
65
77
|
Read commands:
|
|
66
78
|
get <recipe_id> Fetch recipe code → recipe_<id>_code.json
|
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.
|
|
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;
|
|
@@ -143,6 +158,30 @@ function apiTriggerConfig() {
|
|
|
143
158
|
];
|
|
144
159
|
}
|
|
145
160
|
|
|
161
|
+
// ── Setup commands ────────────────────────────────────────────────────────────
|
|
162
|
+
|
|
163
|
+
function cmdBootstrapClaude(destDir) {
|
|
164
|
+
const src = path.join(__dirname, 'CLAUDE.md');
|
|
165
|
+
const dest = path.join(destDir ?? process.cwd(), 'CLAUDE.md');
|
|
166
|
+
fs.copyFileSync(src, dest);
|
|
167
|
+
console.log(`CLAUDE.md written to ${dest}`);
|
|
168
|
+
return dest;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function cmdAuth(token, destDir) {
|
|
172
|
+
const envPath = path.join(destDir ?? process.cwd(), '.env');
|
|
173
|
+
let content = fs.existsSync(envPath) ? fs.readFileSync(envPath, 'utf8') : '';
|
|
174
|
+
const line = `WORKATO_API_TOKEN=${token}`;
|
|
175
|
+
if (/^WORKATO_API_TOKEN=/m.test(content)) {
|
|
176
|
+
content = content.replace(/^WORKATO_API_TOKEN=.*/m, line);
|
|
177
|
+
} else {
|
|
178
|
+
content = content ? content.trimEnd() + '\n' + line + '\n' : line + '\n';
|
|
179
|
+
}
|
|
180
|
+
fs.writeFileSync(envPath, content);
|
|
181
|
+
console.log(`Token saved to ${envPath}`);
|
|
182
|
+
return envPath;
|
|
183
|
+
}
|
|
184
|
+
|
|
146
185
|
// ── Read commands ─────────────────────────────────────────────────────────────
|
|
147
186
|
|
|
148
187
|
async function cmdGet(recipeId) {
|
|
@@ -307,12 +346,14 @@ async function cmdDelete(recipeId) {
|
|
|
307
346
|
|
|
308
347
|
module.exports = {
|
|
309
348
|
// config
|
|
310
|
-
loadEnv, setConfig, getToken,
|
|
349
|
+
loadEnv, setConfig, getToken, resolveBaseUrl, readProjectConfig,
|
|
311
350
|
// http
|
|
312
351
|
apiGet, apiPost, apiPut, apiDelete,
|
|
313
352
|
// helpers
|
|
314
353
|
findStep, deepMerge, extractCode,
|
|
315
354
|
apiTriggerCode, apiTriggerConfig,
|
|
355
|
+
// setup commands
|
|
356
|
+
cmdBootstrapClaude, cmdAuth,
|
|
316
357
|
// read commands
|
|
317
358
|
cmdGet, cmdListRecipes, cmdListProjects, cmdListFolders,
|
|
318
359
|
cmdListConnections, cmdListDataTables, cmdGetDataTable,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "workato-dev-api",
|
|
3
|
-
"version": "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,245 @@ 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
|
+
|
|
1086
|
+
// ── cmdBootstrapClaude ────────────────────────────────────────────────────────
|
|
1087
|
+
|
|
1088
|
+
describe('cmdBootstrapClaude', () => {
|
|
1089
|
+
function tmpDir() {
|
|
1090
|
+
const d = path.join(os.tmpdir(), `workato-test-${Date.now()}-${Math.random()}`);
|
|
1091
|
+
fs.mkdirSync(d, { recursive: true });
|
|
1092
|
+
return d;
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
test('copies CLAUDE.md into the destination directory', () => {
|
|
1096
|
+
const dir = tmpDir();
|
|
1097
|
+
try {
|
|
1098
|
+
lib.cmdBootstrapClaude(dir);
|
|
1099
|
+
assert.ok(fs.existsSync(path.join(dir, 'CLAUDE.md')), 'CLAUDE.md should exist in dest dir');
|
|
1100
|
+
} finally {
|
|
1101
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
1102
|
+
}
|
|
1103
|
+
});
|
|
1104
|
+
|
|
1105
|
+
test('written file content matches the source CLAUDE.md', () => {
|
|
1106
|
+
const dir = tmpDir();
|
|
1107
|
+
try {
|
|
1108
|
+
lib.cmdBootstrapClaude(dir);
|
|
1109
|
+
const srcPath = path.join(__dirname, '..', 'CLAUDE.md');
|
|
1110
|
+
const src = fs.readFileSync(srcPath, 'utf8');
|
|
1111
|
+
const dest = fs.readFileSync(path.join(dir, 'CLAUDE.md'), 'utf8');
|
|
1112
|
+
assert.equal(dest, src);
|
|
1113
|
+
} finally {
|
|
1114
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
1115
|
+
}
|
|
1116
|
+
});
|
|
1117
|
+
|
|
1118
|
+
test('returns the destination file path', () => {
|
|
1119
|
+
const dir = tmpDir();
|
|
1120
|
+
try {
|
|
1121
|
+
const result = lib.cmdBootstrapClaude(dir);
|
|
1122
|
+
assert.equal(result, path.join(dir, 'CLAUDE.md'));
|
|
1123
|
+
} finally {
|
|
1124
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
1125
|
+
}
|
|
1126
|
+
});
|
|
1127
|
+
|
|
1128
|
+
test('overwrites an existing CLAUDE.md', () => {
|
|
1129
|
+
const dir = tmpDir();
|
|
1130
|
+
try {
|
|
1131
|
+
fs.writeFileSync(path.join(dir, 'CLAUDE.md'), 'old content');
|
|
1132
|
+
lib.cmdBootstrapClaude(dir);
|
|
1133
|
+
const content = fs.readFileSync(path.join(dir, 'CLAUDE.md'), 'utf8');
|
|
1134
|
+
assert.notEqual(content, 'old content');
|
|
1135
|
+
} finally {
|
|
1136
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
1137
|
+
}
|
|
1138
|
+
});
|
|
1139
|
+
});
|
|
1140
|
+
|
|
1141
|
+
// ── cmdAuth ───────────────────────────────────────────────────────────────────
|
|
1142
|
+
|
|
1143
|
+
describe('cmdAuth', () => {
|
|
1144
|
+
function tmpDir() {
|
|
1145
|
+
const d = path.join(os.tmpdir(), `workato-auth-test-${Date.now()}-${Math.random()}`);
|
|
1146
|
+
fs.mkdirSync(d, { recursive: true });
|
|
1147
|
+
return d;
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
test('creates .env with token when file does not exist', () => {
|
|
1151
|
+
const dir = tmpDir();
|
|
1152
|
+
try {
|
|
1153
|
+
lib.cmdAuth('mytoken123', dir);
|
|
1154
|
+
const content = fs.readFileSync(path.join(dir, '.env'), 'utf8');
|
|
1155
|
+
assert.ok(content.includes('WORKATO_API_TOKEN=mytoken123'));
|
|
1156
|
+
} finally {
|
|
1157
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
1158
|
+
}
|
|
1159
|
+
});
|
|
1160
|
+
|
|
1161
|
+
test('returns the .env file path', () => {
|
|
1162
|
+
const dir = tmpDir();
|
|
1163
|
+
try {
|
|
1164
|
+
const result = lib.cmdAuth('tok', dir);
|
|
1165
|
+
assert.equal(result, path.join(dir, '.env'));
|
|
1166
|
+
} finally {
|
|
1167
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
1168
|
+
}
|
|
1169
|
+
});
|
|
1170
|
+
|
|
1171
|
+
test('updates existing WORKATO_API_TOKEN line in .env', () => {
|
|
1172
|
+
const dir = tmpDir();
|
|
1173
|
+
try {
|
|
1174
|
+
fs.writeFileSync(path.join(dir, '.env'), 'WORKATO_API_TOKEN=oldtoken\n');
|
|
1175
|
+
lib.cmdAuth('newtoken', dir);
|
|
1176
|
+
const content = fs.readFileSync(path.join(dir, '.env'), 'utf8');
|
|
1177
|
+
assert.ok(content.includes('WORKATO_API_TOKEN=newtoken'), 'should have new token');
|
|
1178
|
+
assert.ok(!content.includes('oldtoken'), 'should not have old token');
|
|
1179
|
+
assert.equal((content.match(/WORKATO_API_TOKEN=/g) || []).length, 1, 'only one token line');
|
|
1180
|
+
} finally {
|
|
1181
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
1182
|
+
}
|
|
1183
|
+
});
|
|
1184
|
+
|
|
1185
|
+
test('appends token to .env that has other keys but no WORKATO_API_TOKEN', () => {
|
|
1186
|
+
const dir = tmpDir();
|
|
1187
|
+
try {
|
|
1188
|
+
fs.writeFileSync(path.join(dir, '.env'), 'OTHER_KEY=value\n');
|
|
1189
|
+
lib.cmdAuth('mytoken', dir);
|
|
1190
|
+
const content = fs.readFileSync(path.join(dir, '.env'), 'utf8');
|
|
1191
|
+
assert.ok(content.includes('OTHER_KEY=value'), 'existing key preserved');
|
|
1192
|
+
assert.ok(content.includes('WORKATO_API_TOKEN=mytoken'), 'token appended');
|
|
1193
|
+
} finally {
|
|
1194
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
1195
|
+
}
|
|
1196
|
+
});
|
|
1197
|
+
|
|
1198
|
+
test('token value containing = is preserved verbatim', () => {
|
|
1199
|
+
const dir = tmpDir();
|
|
1200
|
+
try {
|
|
1201
|
+
lib.cmdAuth('tok==extra==', dir);
|
|
1202
|
+
const content = fs.readFileSync(path.join(dir, '.env'), 'utf8');
|
|
1203
|
+
assert.ok(content.includes('WORKATO_API_TOKEN=tok==extra=='));
|
|
1204
|
+
} finally {
|
|
1205
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
1206
|
+
}
|
|
1207
|
+
});
|
|
1208
|
+
|
|
1209
|
+
test('preserves other keys in .env when updating token', () => {
|
|
1210
|
+
const dir = tmpDir();
|
|
1211
|
+
try {
|
|
1212
|
+
fs.writeFileSync(path.join(dir, '.env'), 'FOO=bar\nWORKATO_API_TOKEN=old\nBAZ=qux\n');
|
|
1213
|
+
lib.cmdAuth('updated', dir);
|
|
1214
|
+
const content = fs.readFileSync(path.join(dir, '.env'), 'utf8');
|
|
1215
|
+
assert.ok(content.includes('FOO=bar'), 'FOO preserved');
|
|
1216
|
+
assert.ok(content.includes('BAZ=qux'), 'BAZ preserved');
|
|
1217
|
+
assert.ok(content.includes('WORKATO_API_TOKEN=updated'), 'token updated');
|
|
1218
|
+
} finally {
|
|
1219
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
1220
|
+
}
|
|
1221
|
+
});
|
|
1222
|
+
});
|
|
1223
|
+
|
|
985
1224
|
// Restore console at end
|
|
986
1225
|
process.on('exit', () => {
|
|
987
1226
|
console.log = origLog;
|