#
# Webida Restful Api specifiaion
#

# Current api desingn rules
#  1) Any (and only) "reusable" schemas should be placed in #/parameters, #/definitions
#  2) Do not use multiple tags in a single operaion to reduce client code size
#  3) All "real-path" parameters (can contain /) should be "relative".
#     An operation can have 0 or 1 real-path parameters, at the end of path params.
#  4) Prefer /some-name-plural/{id} form (except wfs) and don"t mix with sigular noun
#  5) All response should be an object or file. No Plain Text!
#  6) Keep common/starndard http status code semantic, as possible as we can.
#  7) Do not split this document into pieces, for none of standard swagger tools supoorts
#     multi-docs spec yet.
#  8) Do not use "polymorphism" with discriminator property. swagger-codegen for JS does
#     not support such polymorphism yet.

# notes for swaggerize-routes
#  - 1 x-handler impl module for every operation. file name should be same to operation id.

swagger: "2.0"

info:
  version: "0.7.1"
  title: Webida Restful API
  description: Restful API for Webida clients to use server's data & features
  license:
    name: Apache 2.0
    url: http://www.apache.org/licenses/LICENSE-2.0.html

# Should not include host / schemes in this spec when publishing,
#  for server/client implementations 'ALWAYS' tend to override the value to current
#  service url.

basePath: /api

produces:
  - application/json
  - application/octet-stream

consumes:
  - application/json

paths:

  /auth/login:
    post:
      x-handler: handlers/auth/login.js
      tags: ["auth"]
      description: |
        A "VERY" basic authentication, required to use webida-simple-auth security scheme.

        Service / Product implementations who need better security, should override this operation or add their own login api or some other specs like OAuth2. Simple auth is not suitable for large-sacle, multi-tennant service, for the scheme assumes a single, trusted user only.

        Logging-in with master token, the generated access token inherits all restriction from it. On the other hand, normal log-in with login id & password creates an unrestricted access token, with reasonably short expiration time.

        Every client should spawn another access token with issueToken API before current access token expires, inheriting session id from current token. To save remote access info, client should create a (restricted but long-ttl) master token to start IDE from remote. The remote client should not use the unrestricted acccess token from login to use any other perpose than finding available workspaces, and should not refresh the token. (Let user log-in again)

        Login API does not force any encryption. Server should provide secure transport channel, usually https, to provide remote access, always.
      operationId: login
      parameters:
        - name: body
          in: body
          required: true
          schema:
            $ref: "#/definitions/Credential"
      responses:
        "200":
          description: login success
          schema:
            $ref: "#/definitions/Token"
        default:
          description: Error
          schema:
            $ref: "#/definitions/RestError"

  /auth/info:
    get:
      x-handler: handlers/auth/getInfo.js
      tags: ["auth"]
      description: |
        Gets user information of that can be identified with current access token. Implementations should provide a more restful api based on domain data model, not extending this operation. (e.g. GET,PUT and DELETE on /Users/{userId} to read, update and delete user)
      operationId: getInfo
      security:
        - webida-simple-auth: []
      responses:
        "200":
          description: user information
          schema:
            $ref: "#/definitions/User"
        "401":
          description: auth failed
          schema:
            $ref: "#/definitions/RestError"
        default:
          description: Error
          schema:
            $ref: "#/definitions/RestError"

  /auth/token:
    post:
      x-handler: handlers/auth/issueToken.js
      tags: ["auth"]
      description: |
        Creates new token from current access token, inheriting workspace id & session id. The duration of generated token is not (and should not be) parameterizable. Server should set proper duration, respecting "reconnect" period of socket.io clients. Remember that most of socket.io client implementations (including official js client) do not provide any ways to change connection parameters (header or query) while reconnecting to server.

        Like login API, this endpoint does not provide any encryption. Server should not set any data to harm security in the token & should provide some signinig/encryption mechanism to protect token. Simple JSON Web Token with HMAC-SHA will do.

      operationId: issueToken
      security:
        - webida-simple-auth: []
      parameters:
        - name: type
          in: query
          required: true
          type: string
          enum: ["MASTER", "ACCESS"]
        - name: workspaceId
          in: query
          required: false
          type: string
          description: Clients to save some remote access info should issue a MASTER type token restricted to specific workspace id.
      responses:
        "200":
          description: new token generated
          schema:
            $ref: "#/definitions/Token"
        default:
          description: Error
          schema:
            $ref: "#/definitions/RestError"


  # Basic WFS operations , read/write file, create dir, delete, copy, move, ...
  #  wfs paths starts with /wfs/{wfsId}
  #  /file/{wfsPath} file CRUD C,U is PUT, not POST
  #    GET - read file
  #    PUT - write file
  #  /dir/{wfsPath} directory CRUD
  #    GET - list (tree) dir
  #    PUT - create (can  be expanded to import, later)
  #  /any/{wfsPath}
  #    GET?{ignoreError} - stat / exists
  #    PUT?{src} - copy
  #    POST?{src} - move
  #    DELETE - remove
  #  /ops/search?{wfsPathQuery} for search (GET) and replace (POST)
  #  /ops/replace?{wfsPathQuery} for search (GET) and replace (POST)

  # WFS File operations - read/write
  /wfs/{wfsId}/file/{wfsPath}:
    # readFile.
    get:
      x-handler: handlers/wfs/readFile.js
      tags: ["wfs"]
      description: read file data on path
      operationId: readFile
      security:
        - webida-simple-auth: []
      parameters:
        - $ref: "#/parameters/wfsId"
        - $ref: "#/parameters/wfsPath"
        - name: If-Modified-Since
          in: header
          required: false
          description: Usual if-modified-since header. So, should be RFC-1123(same to RFC-822) format, not RFC-3339 (same to ISO-8601).
          type: string
        - name: If-None-Match
          in: header
          required: false
          description: Usual if-non-match header, allowing only 1 e-tag value from previous readFile response. The value of this header can have weak prefix and quotation chars. This header value precedes the value of if-modified-since header. Server should ignore if-modified-since header when if-none-match header exists, as RFC-2616.
          type: string
      responses:
        "200":
          description: File contents. Content-Type is application/octet-stream or follows file name extension.
          schema:
            type: file
          headers:
            ETag:
              description: usual etag header in HTTP 1.1
              type: string
            Last-Modified:
              description: usual last-modified header, in RFC-1123 format.
              type: integer
        default:
          description: Error
          schema:
            $ref: "#/definitions/RestError"

    # writeFile
    put:
      x-handler: handlers/wfs/writeFile.js
      tags: ["wfs"]
      description: Creates / updates file with body data. Server should write the file in atomic manner nd should not write down request body into final destination path directly. In other words,  wheather writeFile() succeeds or not, the contents of the file should not be corrupted nor half-written.
      operationId: writeFile
      consumes:
        - multipart/form-data
      security:
        - webida-simple-auth: []
      parameters:
        - $ref: "#/parameters/wfsId"
        - $ref: "#/parameters/wfsPath"
        - $ref: "#/parameters/ensureParents"
        - name: data
          in: formData
          required: true
          description: file contents to write.
          type: file
      responses:
        "200":
          description: OK
          schema:
            $ref: "#/definitions/RestOK"
        default:
          description: Error
          schema:
            $ref: "#/definitions/RestError"

  # WFS Dir operations - list(tree) and create empty one
  /wfs/{wfsId}/dir/{wfsPath}:
    # dirTree
    get:
      x-handler: handlers/wfs/dirTree.js
      tags: ["wfs"]
      description: Returns a directory tree of given path, the errors while building sub-tree will be ignored and result will not include the path that has errors. Client may have to stat some suspicious paths manually, if listing is not complete.
      operationId: dirTree
      security:
        - webida-simple-auth: []
      parameters:
        - $ref: "#/parameters/wfsId"
        - $ref: "#/parameters/wfsPath"
        - name: maxDepth
          description: Maximum depth of tree. -1 to build a full tree, 0 to stat, 1 to plain list.
          in: query
          type: integer
          required: true
      responses:
        "200":
          description: A DirEntry, root of the tree, for given path and depth.
          schema:
            $ref: "#/definitions/DirEntry"
        default:
          description: Error
          schema:
            $ref: "#/definitions/RestError"

    # createDir
    put:
      x-handler: handlers/wfs/createDir.js
      tags: ["wfs"]
      description: Creates a directory at the path. When the path is found to be a directory, this api does not return error and does not care it's empty or not. Always creates parent directories if needed.
      operationId: createDir
      security:
        - webida-simple-auth: []
      parameters:
        - $ref: "#/parameters/wfsId"
        - $ref: "#/parameters/wfsPath"
      responses:
        "200":
          description: OK
          schema:
            $ref: "#/definitions/RestOK"
        default:
          description: Error
          schema:
            $ref: "#/definitions/RestError"

  # WFS Any operations - stat & exist, copy, move, remove
  /wfs/{wfsId}/any/{wfsPath}:
    # stat
    get:
      x-handler: handlers/wfs/stat.js
      tags: ["wfs"]
      description: Get stats of given path. (stat() returns stats object in node and POSIX system). This API should be called only when stats of some file system path is stale for unknown reason (e.g. losting change events). Use dirTree operation and session events to detect stats, if possible. This API can be used to check a path is valid, existing one, but it's not recommended to check existence of individual paths by API. Clients should use dirTree and session events to synchorize some in-app file system with webida file system.
      operationId: stat
      security:
        - webida-simple-auth: []
      parameters:
        - $ref: "#/parameters/wfsId"
        - $ref: "#/parameters/wfsPath"
        - name: dummyFor404
          in: query
          required: false
          description: When true, operation ignore ENOENT error and returns DUMMY stats object instead of 404 error.
          type: boolean
          default: false
      responses:
        "200":
          description: stats object.
          schema:
            $ref: "#/definitions/Stats"
        default:
          description: Error
          schema:
            $ref: "#/definitions/RestError"

    # copy
    put:
      x-handler: handlers/wfs/copy.js
      tags: ["wfs"]
      description: |
        Creates a copy of source to given path. Unlike cp command, wfsPath always denotes an exact path of the resource to be created.

        So, When destination path exists already,
          1) copying file to file : follows noOverwrite flag. (does not return error)
          2) copying file to dir : returns 409 error
          3) copying dir to file : returns 409 error
          4) copying dir to dir : merge srcPath/* to wfsPath, following noOverwite flag.

        This operation creates the parents dir of destination path always, and does not roll-back the creation when operation failed. So, clients should roll-back if needed.

      operationId: copy
      security:
        - webida-simple-auth: []
      parameters:
        - $ref: "#/parameters/wfsId"
        - $ref: "#/parameters/wfsPath"
        - $ref: "#/parameters/srcPath"
        - $ref: "#/parameters/noOverwrite"
        - name: followSymbolicLinks
          in: query
          description: dereference symlinks in source.
          required: false
          type: boolean
          default: false
        - name: preserveTimestamps
          in: query
          description: keep mtime/atime of source file(s) in destination.
          required: false
          type: boolean
          default: false
      responses:
        "200":
          description: OK
          schema:
            $ref: "#/definitions/RestOK"
        default:
          description: Error
          schema:
            $ref: "#/definitions/RestError"

    # move
    post:
      x-handler: handlers/wfs/move.js
      tags: ["wfs"]
      description: Moves source resource to given path. Follows same rule to deal with existing path. So, this operation works like rename rather than mv. Just like copy(), this operations creates paraent dirs if needed and does not roll-back. Symbolic link and timestamp values will be moved without touching.
      operationId: move
      security:
        - webida-simple-auth: []
      parameters:
        - $ref: "#/parameters/wfsId"
        - $ref: "#/parameters/wfsPath"
        - $ref: "#/parameters/srcPath"
        - $ref: "#/parameters/noOverwrite"
      responses:
        "200":
          description: OK
          schema:
            $ref: "#/definitions/RestOK"
        default:
          description: Error
          schema:
            $ref: "#/definitions/RestError"

    # remove / delete
    delete:
      x-handler: handlers/wfs/remove.js
      tags: ["wfs"]
      description: delete file or directory
      operationId: remove
      security:
        - webida-simple-auth: []
      parameters:
        - $ref: "#/parameters/wfsId"
        - $ref: "#/parameters/wfsPath"
        - name: noRecursive
          in: query
          required: false
          description: if set, deleting non-empty directory will return 409 error.
          type: boolean
          default: false
      responses:
        "200":
          description: OK
          schema:
            $ref: "#/definitions/RestOK"
        default:
          description: Error
          schema:
            $ref: "#/definitions/RestError"

  # WFS search operation
  /wfs/{wfsId}/ops/search:
    get:
      x-handler: handlers/wfs/search.js
      tags: ["wfs"]
      description: search files in some path, with given pattern
      operationId: search
      security:
        - webida-simple-auth: []
      parameters:
        - $ref: "#/parameters/wfsId"
        - $ref: "#/parameters/wfsPathList"
        - $ref: "#/parameters/pattern"
        - $ref: "#/parameters/ignoreCase"
      responses:
        "200":
          description: search
          schema:
            type: object
            additionalProperties:
              type: array
              items:
                $ref: "#/definitions/Match"
        default:
          description: Error
          schema:
            $ref: "#/definitions/RestError"

  # WFS replace operation
  /wfs/{wfsId}/ops/replace:
    post:
      x-handler: handlers/wfs/replace.js
      tags: ["wfs"]
      description: replace file contents with regex matching
      operationId: replace
      security:
        - webida-simple-auth: []
      parameters:
        - $ref: "#/parameters/wfsId"
        - $ref: "#/parameters/wfsPathList"
        - $ref: "#/parameters/pattern"
        - $ref: "#/parameters/ignoreCase"
        - name: replaceTo
          in: query
          description: string to replace with
          type: string
          required: true
      responses:
        "200":
          description: done
          schema:
            $ref: "#/definitions/RestOK"
        default:
          description: Error
          schema:
            $ref: "#/definitions/RestError"

  #  workspace management operations
  #  workspaces/{workspaceId} - individual local workspaces
  #   GET : find workspaces
  #   POST: create workspace
  #   PUT : update single workspace
  #   DELETE : delete single workspace
  /workspaces/{workspaceId}:
    # findWorkspaces
    get:
      x-handler: handlers/workspace/findWorkspaces.js
      tags: ["workspace"]
      description: |
        Finds workspaces with given id or parameters. if workspaceId = '*', all workspaces in server are returned. No empty workspace id is allowed for it's a path parameter. When workspaceId is not '*', server should return empty array, not 404 Not Found error.
      operationId: findWorkspaces
      security:
        - webida-simple-auth: []
      parameters:
        - $ref: "#/parameters/workspaceId"
        - name: includeEphemeral
          in: query
          required: false
          description: flag to include ephemeral workspaces or not, when workspaceId is '*'. if workspace id is specified, then this flag will be ignored.
          type: boolean
          default: false
      responses:
        "200":
          description: array of local workspaces found
          schema:
            type: array
            items:
              $ref: "#/definitions/Workspace"
        default:
          description: Error
          schema:
            $ref: "#/definitions/RestError"

    # createWorkspace
    post:
      x-handler: handlers/workspace/createWorkspace.js
      tags: ["workspace"]
      description: |
        Creates a new workspace with given local path. Requires an unrestricted access token. the workspace id parameter is ignored and will be replaced by new, unique value by server. it's recommended to set the value to simple, bogus one, like '*' or '-' (since it's path  parameter, empty value is not allowed. excludedPath property is initialized with  default values (usually .git/, .node_modules/, ./bower_components) by server.

        Needs an unrestricted access token.
      operationId: createWorkspace
      security:
        - webida-simple-auth: []
      parameters:
        - $ref: "#/parameters/workspaceId"
        - name: localPath
          in: query
          required: true
          description: a real, local path of the system (not unixified)
          type: string
        - name: name
          in: query
          required: true
          description: workspace name property
          type: string
        - name: description
          in: query
          required: true
          description: workspace name property
          type: string
      responses:
        "200":
          description: newly created local workspace
          schema:
            $ref: "#/definitions/Workspace"
        default:
          description: Error
          schema:
            $ref: "#/definitions/RestError"

    # update workspace
    put:
      x-handler: handlers/workspace/updateWorkspace.js
      tags: ["workspace"]
      description: |
        Updates workspace. Some protected properties will not be changed by this op. If server cannot apply changed properties before returning workspace, such properties should not be updated with this operation. Clients should not rely on request body for further works, and should always check response to see what's changed actually.

        Requires proper access rights.
      operationId: updateWorkspace
      security:
        - webida-simple-auth: []
      parameters:
        - $ref: "#/parameters/workspaceId"
        - name: body
          in: body
          description: workspace object that contains updates
          required: true
          schema:
            $ref: "#/definitions/Workspace"
      responses:
        "200":
          description: updated Workspace object. some properties may different from input.
          schema:
            $ref: "#/definitions/Workspace"
        default:
          description: Error
          schema:
            $ref: "#/definitions/RestError"

    # delete workspace
    delete:
      x-handler: handlers/workspace/removeWorkspace.js
      tags: ["workspace"]
      description: |
        Removes a workspace. If no sessions are connected, this api 'works' before returning result. if some sesions are, workspace will be removed when
          1) all sessions are closed for request (will be notified by server)
          2) exceeded time limit value in closeAfter parameter
          3) server stops after accepting remove request
        and willBeRemoved value is set. So, client may 'find' the workspace to be removed after calling this operation.

        Requires "unrestricted" access rights.
      operationId: removeWorkspace
      security:
        - webida-simple-auth: []
      parameters:
        - $ref: "#/parameters/workspaceId"
        - name: closeAfter
          in: query
          description: Time in seconds to wait for all sessions save & close their data.
          type: integer
          required: false
          default: 0
        - name: removeDir
          in: query
          description: flag to delete directory in real file system when removing workspace. Usually, this value should not be set true for user can handle directory persistence manually. Clients need to get explicit confirmation from user.
          type: boolean
          required: false
      responses:
        "200":
          description: OK. removed
          schema:
            $ref: "#/definitions/RestOK"
        default:
          description: Error
          schema:
            $ref: "#/definitions/RestError"

  # workspace - exec operations
  #  workspaces/{workspaceId}/exec
  #   GET : findProcs
  #   POST: exec
  #   DELETE : cancel (for async exec only)
  /workspaces/{workspaceId}/procs:
    #findProcs
    get:
      x-handler: handlers/workspace/findProcs.js
      tags: ["workspace"]
      description: |
        Gets process info on this workspace. To find all child processes, set id to '*'. This op does not returns error when no procs found but empty result array. Child process can be created by exec operation and by some other means.
      operationId: findProcs
      parameters:
        - $ref: "#/parameters/workspaceId"
        - $ref: "#/parameters/execId"
        - name: includeForeground
          in: query
          description: flag to include 'foreground processes' in result. foreground processes can be created by and only by exec operation without async opetion. normally, this flag will not be used except debugging or diagnostics. foreground processes has 'foreground' property, set to true, always.
          type: boolean
          required: false
      responses:
        "200":
          description: the child processes found. result does not include 'exited' procs.
          schema:
            type: array
            items:
              $ref: "#/definitions/ChildProcess"
        default:
          description: Error
          schema:
            $ref: "#/definitions/RestError"

    #exec
    post:
      x-handler: handlers/workspace/execute.js
      tags: ["workspace"]
      description: Executes a shell command (foreground process) or spawns a background process on this workspace. Requires proper access rights.
      operationId: execute
      security:
        - webida-simple-auth: []
      parameters:
        - $ref: "#/parameters/workspaceId"
        - name: async
          in: query
          description: Spawns a background process for given command and returns the created child proc info. Actual output (stream of message) will be delivered to web socket channel, using execution id.
          type: boolean
          required: false
          default: false
        - name: body
          in: body
          description: the process to be executed or spawned.
          required: true
          schema:
            $ref: "#/definitions/Execution"
      responses:
        "200":
          description: Execution result with all captured standard ouput and error. If execution is completed without error, the error property in result object should be a falsy value. If some error has happened, then it will be an error message, without stack. A plain RestError will be returned with 4xx or 5xx error code (e.g. insufficient/invalid arguments) when it's found before creating process. So, clients should handle the 'invocation error' and 'errors from the command' differently.
          schema:
            $ref: "#/definitions/ExecutionResult"
        "201":
          description: Spawned process infomation created by async execution. If server could not create a child process, error event will be sent to client via socket channel but RestError will not be ruturned from this operation. When a client has got 'error' event from the socket channel, the client should close the channel wheather it receives subsequent exit event or not (with some proper timeout if needed). Server should not send the errors related to 'killing' child processes.
          schema:
            $ref: '#/definitions/ChildProcess'
        default:
          description: Error
          schema:
            $ref: "#/definitions/RestError"

    #cancel
    delete:
      tags: ["workspace"]
      description: Cancels executions, killing the spawned processes. To terminate all spawned processes, set execId to '*'. Requires proper access rights. Since killing a process usually takes a little bit long time, this api does not returns actual result but works in async manner. (So, client should listen to web socket channels for the processes). This operation Requires same access rights to execute operation. Server should reject to cancel any forground processes and processes is being killed or has exited already.
      operationId: cancel
      security:
        - webida-simple-auth: []
      parameters:
        - $ref: "#/parameters/workspaceId"
        - $ref: "#/parameters/execId"
      responses:
        "200":
          description: OK
          schema:
            $ref: "#/definitions/RestOK"
        default:
          description: Error
          schema:
            $ref: "#/definitions/RestError"

  # remote-access operations
  #   GET : get all remote workspaces" access info, registered to local server
  #   PUT : put (upsert) a remote workspace access info
  #   DELETE : delete single remote workspace" access info
  /remotes:
    # findRemoteAccess
    get:
      x-handler: handlers/remotes/findRemoteAccesses.js
      tags: ["remotes"]
      description: Get all access informations See RemoteWorkspaceAccess definition for details (no fancy find / search feature yet)
      operationId: findRemoteAccesses
      security:
        - webida-simple-auth: []
      responses:
        "200":
          description: Array of remote workspaces
          schema:
            type: array
            items:
              $ref: "#/definitions/RemoteAccess"
        default:
          description: Error
          schema:
            $ref: "#/definitions/RestError"

    # putRemoteAccess
    put:
      tags: ["remotes"]
      description: Ceates or updates a remote workspace access information
      operationId: putRemoteAccess
      security:
        - webida-simple-auth: []
      parameters:
        - name: body
          in: body
          required: true
          schema:
            $ref: "#/definitions/RemoteAccess"
      responses:
        "200":
          description: OK
          schema:
            $ref: "#/definitions/RestOK"
        default:
          description: Error
          schema:
            $ref: "#/definitions/RestError"

    # removeRemoteWorkspace
    delete:
      tags: ["remotes"]
      description: Removes remote workspace access information
      operationId: removeRemoteAccess
      security:
        - webida-simple-auth: []
      parameters:
        - name: workspaceId
          in: query
          required: true
          description: workspace Id of remote workspace
          type: string
      responses:
        "200":
          description: removed remote workspace access info
          schema:
            $ref: "#/definitions/RemoteAccess"
        default:
          description: Error
          schema:
            $ref: "#/definitions/RestError"

  # session management operations
  #  GET : find session
  #  DELETE: close session
  /sessions/{sessionId}:
    # findSessions
    get:
      x-handler: handlers/session/findSessions.js
      tags: ["session"]
      description: |
        Finds webida sessions established to server. if session id is given, matched session info will be returned and workspace id  parameter will be ignored. To find all sessions of some workspace, set session id to '*' and specify workspace id.

        This operation requires proper accsss rights.
          1) To find all sessions, an unrestricted token is required.
          2) To find some workspace sesions, token should have proper access right on the workspace.
      operationId: findSessions
      security:
        - webida-simple-auth: []
      parameters:
        - $ref: "#/parameters/sessionId"
        - $ref: "#/parameters/workspaceIdQuery"
      responses:
        "200":
          description: array of sessions
          schema:
            type: array
            items:
              $ref: "#/definitions/Session"
        default:
          description: Error
          schema:
            $ref: "#/definitions/RestError"

    # closeSessions
    delete:
      x-handler: handlers/session/closeSession.js
      tags: ["session"]
      description: Closes session with timeout. Targets are selected by same rule to findSessions() op. While targeting multiple sessions, this operation requires same access rights with findSessions(). Closing a single session requires 'same session id' or 'unrestricted workspace acceess'.
      operationId: closeSessions
      security:
        - webida-simple-auth: []
      parameters:
        - $ref: "#/parameters/sessionId"
        - $ref: "#/parameters/workspaceIdQuery"
        - name: closeAfter
          in: query
          type: integer
          description: |
            Waiting time before actual closing, to let client save files and prevent reconnecting.
          required: true
      responses:
        "200":
          description: OK.
          schema:
            $ref: "#/definitions/RestOK"
        default:
          description: Error
          schema:
            $ref: "#/definitions/RestError"
    # no POST or PUT, for session should be created or updated by web-socket

  /aliass/{aliasId}:
    # findAliases
    get:
      x-handler: handlers/alias/findAliasesjs
      tags: ["alias"]
      description: get alias objects. set aliasId to '*' to find all aliases in some workspace. If alias id is given, only 0 or 1 matched alias object will be returned, ignoring workspaceId and srcPath. To get an alias object of some wfs path, set srcPath value to some path, and to find all aliases in a workspace, set it to '*' (empty value is not allowed by definition)
      operationId: findAliases
      security:
        - webida-simple-auth: []
      parameters:
        - $ref: "#/parameters/aliasId"
        - $ref: "#/parameters/workspaceIdQuery"
        - $ref: "#/parameters/srcPath"
      responses:
        "200":
          description: alias list
          schema:
            type: array
            items:
                $ref: "#/definitions/Alias"
        default:
          description: Error
          schema:
            $ref: "#/definitions/RestError"

    # putAlias
    put:
      x-handler: handlers/alias/putAlias.js
      tags: ["alias"]
      description: create, or update an alias.
      operationId: putAlias
      security:
        - webida-simple-auth: []
      parameters:
        - $ref: "#/parameters/aliasId"
        - name: body
          in: body
          description: alias object to write. should have same id to aliasId parameter.
          required: true
          schema:
            $ref: "#/definitions/Alias"
      responses:
        "200":
          description: OK.
          schema:
            $ref: "#/definitions/RestOK"
        default:
          description: Error
          schema:
            $ref: "#/definitions/RestError"

    # removeAliases
    delete:
      x-handler: handlers/alias/removeAlias.js
      tags: ["alias"]
      description: remove alias. targeting rule is same to findAliases() operation.
      operationId: removeAliases
      security:
        - webida-simple-auth: []
      parameters:
        - $ref: "#/parameters/aliasId"
        - $ref: "#/parameters/workspaceIdQuery"
        - $ref: "#/parameters/srcPath"
      responses:
        "200":
          description: OK.
          schema:
            $ref: "#/definitions/RestOK"
        default:
          description: Error
          schema:
            $ref: "#/definitions/RestError"

securityDefinitions:
  webida-simple-auth:
    type: apiKey
    name: Authorization
    in: header
    x-authorize: webida-simple-auth.js

parameters:
  wfsId:
    name: wfsId
    in: path
    description: webida file system id (same to workspace id) to access.
    required: true
    type: string

  wfsPath:
    name: wfsPath
    in: path
    description: webida file system path to access. without heading /. should be placed at the end of path arguments
    required: true
    type: string
    pattern: .*

  srcPath:
    name: srcPath
    in: query
    description: source data path of some operations, without have heading /
    required: true
    type: string

  wfsPathList:
    name: wfsPathList
    in: query
    description: array of wfsPath, without heading /.
    required: true
    type: array
    items:
      type: string
    collectionFormat: multi

  ensureParents:
    name: ensureParents
    in: query
    description:  A flag to create all parent directories to create file or dir, like mkdir -p. This parameter does not create entire path, but ensures 'parent directory' of the wfsPath parameter
    type: boolean
    required: false
    default: false

  noOverwrite:
    name: noOverwrite
    in: query
    description: does not overwrites any existing file while copying or moving
    required: false
    type: boolean
    default: false

  pattern:
    name: pattern
    in: query
    description: regex pattern to match in search or replace. In replace operation, pattern should be same to the parttern in search operation
    type: string
    required: true

  ignoreCase:
    name: ignoreCase
    in: query
    description: regex matching option to ignore case. In replace operation, this option should be same to one used in search operation
    type: boolean
    required: false
    default: false

  workspaceId:
    name: workspaceId
    in: path
    description: webida workspace id (usually same to file system id, wfsId)
    required: true
    type: string

  workspaceIdQuery:
    name: workspaceId
    in: query
    description: webida workspace id in query part
    required: true
    type: string

  execId:
    name: execId
    in: query
    description: the id from execution request (different from pid!)
    type: string
    required: true

  sessionId:
    name: sessionId
    in: path
    description: webida session id (usually different from socket id from sock.io)
    required: true
    type: string

  aliasId:
    name: aliasId
    in: path
    description: url path fragment alias id. should have no '/' as well as any 'unsafe' chars for url path.  especially, '*' is reserved for finding operations or some other special case.
    required: true
    type: string

definitions:

  RestOK:
    type: object
    properties:
      message:
        description: additional text from server. Clients may use this value to debugging or logging, but should not rely on the value of this property, for server can omit to set message for performance.
        type: string

  RestError:
    type: object
    description: Error object with code and message. code is bound to status code, but not always same to standard HTTP status text. For example, some 409 error may have code "Invalid Argument" instead of "Conflic". So, Client should read message property to know what happend exactly, when an error is returned from server. And, some 500 errors can have system errno instead of useless "internal". Like other errors, details are hidden in message.
    properties:
      code:
        type: string
      message:
        type: string
      errno:
        description: errno code for some internal errors in server. Since service implementation can use many different platform api & runtime, client should avoid relying on errno code. If server provides errno code, it should be translated into human readable string like ENOENT or ENOMEM, not pure integer value.
        type: string
      stack:
        description: stack trace for this error. Server should not include stack trace in production and client should not print or show this stack to user. This property should be used in 'developer mode' only, for debugging.
        type: string
    required:
      - message

  Token:
    type: object
    description: a json webtoken and accessible data
    properties:
      text:
        type: string
        description: actual token text that should be shipped in header or query
      tokenType:
        type: string
        enum: ["MASTER", "ACCESS"]
        description: |
          MASTER : used to create an access token from clients, without login credential
          ACCESS : protects api access. should be unique for each ide session

          Note that here"s no REFRESH token, nor LOGIN token. The login api will create unrestricted access token & master token pair. Desktop app has a side-way to create an unrestricted master token before starting IDE instances.
      expiresAt:
        type: string
        format: date-time
      issuedAt:
        type: string
        format: date-time
      sessionId:
        type: string
        description: mandatory for ACCESS token, identifying client instance
      workspaceId:
        type: string
        description: If truthy, access rights are restricted to specified workspace only.
    required:
      - text
      - tokenType
      - expiresAt
      - issuedAt

  Credential:
    type: object
    description: User credential to login. Use https to protect credential. master token can replace actual id/password pair.
    properties:
      loginId:
        type: string
      loginPassword:
        type: string
      masterToken:
        type: string
        description: A master token is issued when user wants to access webida api without id/password from remote or local desktop app. When masterToken is set, client should put some bogus id/password for login, non-empty. the values can be used to identify client type.
    required:
      - loginId
      - loginPassword

  User:
    type: object
    description: Any services/products should define some admin apis to manage users in the system and expose what should be exposed to client app. So, no properties are mandatory. Currently, the properties are defined for compatiblity with legacy clients.
    properties:
      id:
        type: string
        description: unique id per user (email is also unique)
      email:
        type: string
      name:
        type: string

  Stats:
    type: object
    description: simplified/augmented fs.Stats class - see node.js doc for all properties
    required:
      - type
      - birthtime
      - mtime
      - mode
      - size
      - nlink
    properties:
      type:
        type: string
        enum:
          - "FILE"
          - "DIRECTORY"
          - "BLOCK_DEVICE"
          - "CHARACTER_DEVICE"
          - "LINK"
          - "FIFO"
          - "SOCKET"
          - "DUMMY"
        description: All types except 'DUMMY' come from fs.Stats is*** methods results. (e.g. if isFile() is true, then type will be 'FILE') If type is not decidable by the methods, default type is 'FILE', for everything on the file system is basically a file. 'DUMMY' type means that some object 'does not exist for now'. Client may use 'DUMMY' type to mark something dangling, not written or created on real file system yet but visible to user.
      birthtime:
        type: string
        format: date-time
      mtime:
        type: string
        format: date-time
      mode:
        type: integer
      size:
        type: integer
      nlink:
        type: integer

  DirEntry:
    type: object
    description: a directory entry (file or directory) with children that represents a (sub) tree
    required:
      - name
      - stats
      - children
    properties:
      name:
        type: string
      stats:
        $ref: "#/definitions/Stats"
      children:
        type: array
        items:
          $ref: "#/definitions/DirEntry"

  Match:
    type: object
    description: search result for a file
    required:
      - line
      - text
    properties:
      line:
        type: integer
      text:
        type: string

  Workspace:
    type: object
    description: A workspace in server
    properties:
      id:
        description: the id of a workspace. usually same to file system id
        type: string
      name:
        description: display text of this workspace for UI
        type: string
      description:
        description: human readable description on this workspace
        type: string
      createdAt:
        description: the time when this workspace is created (registered from local file system)
        type: string
        format: date-time
      accessedAt:
        description: the time when the last session on this workspace was made. (optional)
        type: string
        format: date-time
      workspacePath:
        description: absolute path of this workspace in server. Server may not expose this property to some untrusted clients.
        type: string
      ephemeral:
        description: |
          If set, workspace is ephemeral - Server will drop registration when it stops working. Ususally, side-loaded workspace via desktop app is ephemeral. Client with proper access right can flip this flag to declare the workspace should be persist, after rebooting.
        type: boolean
      excludedPaths:
        description: |
          Ignore patterns to exclude from watch service and search-and-replace operations.

          Pattern follows '.gitignore' syntax, 1 item per line. It should work as a .gitignore file in the workspace directory. Server should remove all comment items (any item that begins with '#') and blank items. Escaping with '\' char for the beginning '!' and ending white-spaces shoule be supported, too.

          To exclude a directory, client may have to put '/' at the end of the item to exclude everything underneath it. When a dir path is excluded with 'ending /', watch service  may not deliver unlinkDir/addDir events for the path and client should manually check the existence or stats.
        type: array
        items:
          type: string
      offlineCachePaths:
        description: |
          Any paths (including excluded paths) to be cached in remote clients.

          Browser client should respect offline cache paths always. Desktop-app client may not use off-line cache for local (embedded) server but shall use cache for any remote servers, even for same host. All caches should be partitioned with workspace id, globally unique value through time and space.

          Client should pre-fetch the contents of offline cache paths when it start IDE sessions on a workspace to use for off-line state. When client goes to off-line, after losing connection to server, it can use cached data as reply of some WFS operations and can write some data to cache to save workspace data & metadata. The changes should be persistent on client side safely. C

          When a client recovers connectivity to server, it should check the stats of files and  dirs to upload if it has got some changes in offline state. If server has more recents contents, client should drop chagnes and refill the cache with fresher data. Client may have some 'time-tolerance' to accept server's data is fresher than client's, smaller than serveral seconds. If server has more recent contents, client should drop the changes and refill the cache with fresher data. If not, client should replay the changes 1 by 1.

          Same protocol should be applied when client application starts with some 'unuploaded change' evertime. That means, client should save 'change history' with 'changed data' too, to process it later, when starting app again in normal condition.

          All Clients should not replay any 'delete' operations while replaying changes on client's cache, to protect from more serious problems with skewed timer or unexpected behaviors. And, of course, client should not rely on cached data while connection state is healthy.
        type: array
        items:
          type: string
    required:
      - id
      - name
      - description
      - createdAt
      - workspacePath
      - excludedPaths
      - offlineCachePaths

  RemoteAccess:
    type: object
    description: Access information of remote workspace in remote server
    properties:
      name:
        description: display text of remote workspace. can be different from original name.
        type: string
      serverUrl:
        description: the url of remote server. Should have no path/query parameters, even "/" in path.
        type: string
      workspaceId:
        description: the id of remote workspace, read from remote server
        type: string
      workspacePath:
        description: Full path of remote workspace, read from remote server. this property will be removed when clients are able to work without "named root directory" in workspace fs tree.
        type: string
      masterToken:
        description: master token to access service, issued from remote server
        type: string
    required:
      - name
      - serverUrl
      - workspaceId
      - masterToken

  Session:
    type: object
    description: an application session per ide instance. bound to access token
    properties:
      id:
        description: the id of a session. usually same to socket id.
        type: string
      name:
        description: human readable name, usually derived from workspace name.
        type: string
      state:
        description: |
          NORMAL = connected, normally working.
          CLOSING = server requested client to disconnect. Connection will be closed soon.
          TERMINATED = disconnected. server will remove this session from registry ASAP.
        type: string
        enum:
          - NORMAL
          - CLOSING
          - TERMINATED
      workspaceId:
        description: the id of workspace that this sessions is working on. If falsy, then this session is not belonged to any workpsace. Usually, dashboard / monitoring app will create a session without workspace id.
        type: string
      clientAddress:
        description: the peer address of session connection. not always
        type: string
      connectedAt:
        description: the time when socket connection is established
        type: string
        format: date-time
      willCloseAt:
        description: when state becomes CLOSING, server sets this time as deadline.
        type: string
        format: date-time
    required:
      - id
      - name
      - state
      - clientAddress
      - connectedAt

  Execution:
    type: object
    description: |
      execution request, simlilar to node.js exec()/spawn(). see node.js documentation for  details of each properties. some properties are not configurable for portability
       * encoding : fixed to utf-8
       * shell : fixed to system defaults. (so, cmd.exe will be invoked in Windows OS, not sh or bash in git-for-windows even they are available.)
       * killSignal : fixed to SIGTERM. If process does not die, server can send SIGKILL or invoke taskkill, to ensure chlid process is killed.
       * uid & gid : will not be set for security
       * stdio : all streams are handled by server. no options are avaliable to client.
       * detached : always false
    properties:
      id:
        description: unique identifier of execution, to demux response stream or cancel request. Server should reject an async exec request without id.
        type: string
      command:
        description: The command to run. Server may not support pipe, redirection nor shell variables in command. Client should not assume any specific shell provider in server and should not using the shell features for portability.

          In windows system with unix sh (e.g. cygwin or mingw from git-for-windows), usually a shell script in PATH may work as command but probably allocates console window while running the command. Implementations (both of server & client) should avoid allocating any  console instances while running services, for costs and UX, and should provide a portable way to invoke commands. Shortly, when a service/product embeds some .sh file to run, it must provide .cmd file doing same thing, always.
        type: string
      args:
        description: |
          The arguments array. Server can join this args to command with proper white-space char, when underlying platform api (e.g. child_process#exec() in node.js) does not support additional arguments vector. It's recommended to use args vector than making a long command, to find & see child processes easily with this Rest API. So, args should be always provided, even empty array.

          When some arguments has a white space (e.g. C:\Program Files\webida), usually invoking command understands escaping or quotation, but not always. Client should add proper escaping or quotation chars to args vector manually. server should not change any command or arguments.
        type: array
        items:
          type: string
      cwd:
        description: Current working directory of spawned process, relative to workspace root. If abscent, cwd will be the workspace directory. Does not accept any evaluatable form like $HOME, %USERPROFILE%. path should be unixified. Server may reject an absolute cwd path.
        type: string
      timeout:
        description: The value which In 'miliseconds' the maximum amount of time the child is allowed to run. (not idle time of stdout / stderr stream) for sync exec. Server should not apply default value for async exec, when omitted. The child process spawned by async       execution should be killed when
           1) server goes down
           2) process exits by self
           3) cancel operation is invoked
        type: integer
        default: 60000
      maxBuffer:
        description: Largest amount of data (in bytes) allowed on stdout or stderr for sync exec. Server should not apply this limit to async execution. In sync exec, server may kill a child process that has exceeded limit. default value is 512KB, large enough.
        type: integer
        default: 524288
    required:
      - command
      - args

  ExecutionResult:
    type: object
    description: execution response
    properties:
      error:
        description: error message when execution failed.
        type: string
      stdout:
        description: standard out of child process.
        type: string
      stderr:
        description: standard error of child process.
        type: string
    required:
      - stdout
      - stderr

  ChildProcess:
    type: object
    description: a process in execution, spawned by exec or other means.
    properties:
      pid:
        description: child process pid
        type: integer
      command:
        description: execution command in execution request
        type: string
      args:
        description: arguments of command in execution request
        type: array
        items:
          type: string
      execId:
        description: execution id from execution request
        type: string
      state:
        description: |
          State of process. Where
            CREATED - process is just created. no event has arrived yet.
            WORKING - some output on stdout/stderr is arrived.
            KILLING - sent kill signal, by cancel operation or some critical error event from the process. Invoking cancel operation to a process being killed should return error.
            EXITED  - This process has exited already. Server is cleaning up the resources and not complete yet. Client should not expect that every exited process can be found with findProcs(). As KILLING state, cancellation will be rejected.
        type: string
        enum:
          - CREATED
          - WORKING
          - KILLING
          - EXITED
      foreground:
        description: if is true, this process is created from synchronous exec request. Som
        type: boolean
      startedAt:
        description: the time when this process is spawned
        type: string
        format: date-time
      exitCode:
        description: the exit code of child process. available with EXITED procs only.
        type: integer
      exitSignal:
        description: the signal named that killed this child process.(not always available)
        type: string
    required:
      - pid
      - command
      - args
      - execId
      - state
      - foreground
      - startedAt

  Alias:
    type: object
    description: alias to access file system using git or direct http(s) requests who can't call swagger api with proper tokens. Implemenations may provide some concrent url formats. Alias may be invalidated when the workspace it belongs is removed. Any removed alias will result 404 error or equivalent.
    properties:
      id:
        description: |
          id, and the path-fragment to access. Since this id is a path-fragment, any unsafe chars for file system path should not be included. Windows OS prohibits following characters.
           < (less than)
           > (greater than)
           : (colon)
           " (double quote)
           / (forward slash)
           \ (backslash)
           | (vertical bar or pipe)
           ? (question mark)
           * (asterisk)
        type: string
      workspaceId:
        description: id of the workspace that contains source of alias
        type: string
      sourcePath:
        description: the source of alias, relative path to workspace root directory.
        type: string
    required:
      - id
      - workspaceId
      - sourcePath
